算法题目打卡:Ques20201004

1. 单峰元素查找

可采用二分查找的思路,优先搜索中间元素,判断其是否大于左右两边的元素,若是,直接返回该元素。否则,判断该元素与相邻元素的上升或下降趋势,若上升,保留右半边。若下降,保留左半边,继续重复上述过程,直到元素数小于3停止递归调用。
 

代码

//给定含有n个不同数的数组L={x1,x2,…,xn},如果L中存在xi,使得x1<x2<…<xi-1<xi>xi+1>…>xn,
// 则称L是单峰的,并称xi是L的峰顶。假设L是单峰的,设计一个优于O(n)的算法找到L的峰顶。

// 思路:采用二分查找的思路,优先搜索中间元素,判断其是否大于左右两边的元素,若是,直接返回该元素。
//否则,判断该元素与相邻元素的上升或下降趋势,若上升,保留右半边。若下降,保留左半边,继续重复上述过程,
//直到元素数小于3停止递归调用

//关键词:单峰 二分 递归 优化少于 O(n)
int siglePeak(int arr[],int left,int right) {

    int mid = left + (right- left)/2;//x + (y - x) / 2

    if(arr[mid]> arr[mid-1]&& arr[mid]> arr[mid+1]) return arr[mid];

    else{

        if(arr[mid-1] < arr[mid]&& arr[mid-2]< arr[mid-1])

            siglePeak(arr,mid+1,right); // 右边

        else if(arr[mid] > arr[mid+1] && arr[mid +1] > arr[mid+2]){

            siglePeak(arr,left,mid-1);

        }

    }   

}

int main(){

    int arr[] = { 1,3,5,8,9,7,6,1,2 };

    cout<<siglePeak(arr,0,8);

return 0;

}

运行效果如下图所示。

根据主定理可知,时间复杂度T(n)=T(n/2)+2,此时该算法复杂度为T(n)=O(logn)。

 

2.找L<x<U的数

 

设A是一个n个不同元素的排好序的数组,给定数L和U,L<U,设计一个优于O(n)的算法,找到A中满足L<x<U的所有数x。

答:利用二分法查找L和U的位置,若找不到,则返回大于L的最小数位置,或小于U的最大数的位置。

代码:

// 二分法 查找插入位置

int searchInsert(int* Array, int left, int right, int target)

{

    while (left <= right)

    {

        int mid = left + (right - left) / 2;

        if (Array[mid] == target) return mid;

        else if (Array[mid] < target)//如果中间值偏小,将初端右移

            left = mid + 1;

        else //中间值偏大则终端左移

            right = mid - 1;

    }

    return left;//如果目标值target比最大值还大,最后left>right,left=nums.size()

    //如果比最小值还小,最后left值为0,因为right会先减为-1后与left交换,left=0且比right大,跳出循环且符合题意,目标值变为初端

}


void printL_U(int * arr,int L,int U,int length) { // length是数组长度

    int i = searchInsert2(arr,1,length,L);

    int j = searchInsert2(arr,1,length,U);

    for (int m = i+1; m <j;m++) {// 输出i+1到j-1的数,因为L<x<U

        cout << arr[m]<<" , ";

    }

}

int main(){

    int arr[] = { 1,1,2,3,5,7,8,9 };

printL_U(arr,1,7,8);  // L=1,U=7 数组长度为8

return 0;

}

运行效果:

3. A∩B

设A={a1,a2,…,an},B={b1,b2,…,bm}是整数集合,其中m=O(logn),设计一个优于O(nm)的算法找出集合C=A∩B。

答:可以将长度较小的数组排序(由于m=O(logn),可知m较小),可选择复杂度较小的排序算法如归并排序,所需时间复杂度为O(mlogm),再将每个B集合的每个元素作为Key,利用二分搜索去排好序的A数组中寻找,查找for循环运行n次,内部的二分搜索O(logm),for循环关键操作O(nlogm),总的时间复杂度T(n)= O(mlogm)+ O(nlogm)= O((m+n)logm)= O(nlogm)

#include <vector>

#include <iostream>

using namespace std;

// 二分查找

void merge(int *arr,int low, int mid, int high) {

    //merge函数将两部分,(分别排好序的子数组),合并成一个,再存于原数组arr

    int h, i, j, k;

    h = low; i = low; j = mid + 1; // h,j作为游标,i指向temp存放数组元素的游标

    vector<int> temp(5); // 这个temp数组是local的,长度为数组arr长度

    while (h <= mid && j <= high) { // 当两个集合都没有取尽时

        if (arr[h] <= arr[j]) {

            temp[i] = arr[h];

            h = h + 1;

        }

        else {

            temp[i] = arr[j];

            j++;

        }

        i++;

    }

    if (h > mid) { // 当第一子组元素被 取尽,而第二组元素未被取尽时

        for (int k = j; k <= high; k++) {

            temp[i] = arr[k];

            i++;

        }

    }

    else { // 当第2组取尽,第一组未被取尽时

        for (int k = h; k <= mid; k++) {

            temp[i] = arr[k];

            i++;

        }

    }

    for (int k = low; k <= high; k++) {//将临时数组temp中的元素再赋值给arr

        arr[k] = temp[k];

    }

}

void mergeSort(int *arr,int low, int high) {

    // arr[low..high]是一个全程数组,含有high-low+1个待排序元素

    if (low < high) {

        int mid = (low + high) / 2;

        mergeSort(arr,low, mid);

        mergeSort(arr,mid + 1, high);

        merge(arr,low, mid, high);

    }

}

int BinarySearch(int *a,int left, int right,int k)//k是要找的数字

{

    int m = left + (right - left) / 2;

    if (left > right)//查找完毕没有找到答案,返回-1

        return -1;

    else

    {

        if (a[m] == k)

            return m;//找到!返回位置.

        else if (a[m] > k)

            return BinarySearch(a,left, m - 1,k);//找左边

        else

            return BinarySearch(a,m + 1, right,k);//找右边

    }

}

int main() {

    int a[] = { 1,5,4,7,8 };

    int b[] = { 4,5,6,10,1,2,3,8,12 };

    vector<int> c ;

    int count=0;

    mergeSort(a,0,4); //归并排序 O(nlogn)

    for (int i = 0; i < 9;i++) {

        int temp=BinarySearch(a, 0, 4, b[i]);

        if (temp != -1) {

            c.push_back(a[temp]);

            count++;

        }

    }

    for (int i = 0; i < c.size();i++) {

        cout << c[i]<<" , ";

    }

         return 0;

}

运行效果:

 

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值