面试复习-------算法与数据结构------二分搜索

面试中的查找算法有顺序查找、二分查找、哈希表查找以及二叉树查找。

哈希表查找通常用在字符串中的字符查找O(1),如:查找字符串中第一个只出现一次的字符。

如果说给定的序列是已经排序(或者是已排序的变种),那么大概率要使用二分查找。


(1)最左查找:给定一个有序(非降序)数组A,可含有重复元素,求最小的i使得A[i]等于target

这个题的直观思路是先找到一个target然后向左遍历,但是这样最坏的时间复杂度可能是O(n);可以使用变形二分搜索

int BinarySearch(vector<int> nums, int target)
{
    if(nums.size() <= 0)return -1;
    int start = 0, end = nums.size()-1;
    while(start < end){
        int mid = start + (end - start)/2;
        if(nums.at(mid) < target)
            start = mid + 1;
        else
            end = mid;  //在中间节点值大于或者等于时,将end更新为中间节点索引
    }
    if(nums.at(start) != target)return -1;
    return start;
}
同理还有最右查找也可以使用这种变形的二分搜索

变形:数字在排序数组中出现的次数(剑指offer38

可以通过求出最左和最右的target得到最终的答案:

int GetFirst(int* data,int start,int end,int k)
{
    if(start>end)
        return -1;

    int middleIndex= (start+end)/2;
    int middleDate= data[middleIndex];

    if(middleDate==k)
    {
        if(middleIndex==start)
            return middleIndex;
        else if(data[middleIndex-1]!=k)
            return middleIndex;
        else
            end=middleIndex-1;
    }
    else if(middleDate>k)
        end=middleIndex-1;
    else
        start=middleIndex+1;
    return GetFirst(data,start,end,k);
}

int GetLast(int* data,int start,int end,int k)
{
    if(start>end)
        return -1;

    int middleIndex=(end+start)/2;
    int middleDate = data[middleIndex];

    if(middleDate==k)
    {
        if(middleIndex==end)
            return middleIndex;
        else if(data[middleIndex+1]!=k)
            return middleIndex;
        else
            start = middleIndex+1;
    }
    else if(middleDate>k)
        end=middleIndex-1;
    else
        start=middleIndex+1;
    return GetLast(data,start,end,k);
}

int GetNum(int* data,int length,int k)
{
    int first=GetFirst(data,0,length-1,k);
    int last =GetLast(data,0,length-1,k);

    if(first==-1 || last==-1)
        return 0;
    return last-first+1;
}

(2)旋转数组的最小数字( 剑指offer8

1,2,3,4,5 --->3,4,5,1,2称为排序数组的旋转

最小数字刚好为两个子数组的分界线

同样可以采用二分搜索的方法,但是需要考虑到数组中可能有重复的数字,即nums.at(index1) == nums.at(index2) == nums.at(mid)这种情况就必须使用顺序搜索

int find2(int ar[],int index1,int index2)
{
    int result=ar[index1];
    for(int i=index1;i<=index2;i++)
    {
        if (ar[i]<result)
            result =ar[i];
    }
    return result;
}

int find_min(int ar[],int length)
{
    if (ar==NULL||length<=0)
        return -1;
    int index1=0;
    int index2=length-1;
    int index_mid;
    if (ar[index1]<ar[index2])//本来就是递增
        return ar[index1];
    while(ar[index1]>=ar[index2])
    {
        if (index2-index1==1)
        {
            return ar[index2];
        }
        index_mid=(index1+index2)/2;

        //若三者都相同无法判断,只能采用顺序查找
        if(ar[index_mid]==ar[index1]  &&  ar[index_mid]==ar[index2])
            return find2(ar,index1,index2);
        if(ar[index_mid]>=ar[index1])
            index1=index_mid;
        if(ar[index_mid]<=ar[index2])
            index2=index_mid;
    }
}
变形:

--------旋转数组中的查找(无重复)(leetcode33

int search(vector<int>& nums, int target) {
        if(nums.size() <= 0)return -1;
        int start = 0;
        int end = nums.size() - 1;
        
        while(start <= end){
            int mid = (start + end)/2;
            if(nums.at(mid) == target)return mid;
            //左半区间有序
            if(nums.at(mid) >= nums.at(start)){
                if(nums.at(mid) >= target && nums.at(start) <= target)end = mid-1;
                else start = mid + 1;
            }
            //右半区间有序
            else{
                if(nums.at(mid) <= target && nums.at(end) >= target)start = mid+1;
                else end = mid -1;
            }
        }
        return -1;
    }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值