二分查找的几种用法

前言

一般我们看到关键字有序数组查找某个值都要下意思的往二分查找上面去想;
当然双指针也是经常用的办法;不过暴力遍历还是别了吧,暴力解法虽然很美滋滋,但是遍历遍历offer就遍历没了;
在这里插入图片描述
下面分享几道剑指offer上面的题目

第一题

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。 链接: link.

思路分析:
在这里插入图片描述
代码

int minArray(int* numbers, int numbersSize){
  int left=0;
  int right=numbersSize-1;
  while(left<right)
  {
      int mid=left+(right-left)/2;
      if(numbers[mid]<numbers[right])
      right=mid;//注意不能-1,小心越过所求值
      else if(numbers[mid]>numbers[right])
      left=mid+1;//始终在左半边,可以+1
      else
      right-=1;//有相等元素
  }
  return numbers[left];
}

第二题

统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8;输出: 2
链接: link.

思路分析:
看到查找数组中的数字的次数,下意识就要反应二分查找;
假设数组中有我们查找的值target,并且有多个,这时候就不能用普通的二分查找来进行了,
这多个目标值肯定是连在一起的,因此我们需要找到这几个连在一起的起始坐标和终止坐标,他们的差值就是我们
需要目标值的个数(注意边界,不同的做法差值不一定正好)),我采用的做法是先找到目标值的右边边界即nums[right-1]=target,
再寻找
target-1的右边边界,即nums[right]=target,
因此两个相减就为目标值的个数;
当寻找第一次右边界的时候,我们可以通过第一次的边界判断是否存在目标值;
如果 第一次寻找的目标值 target<=0||target>=numsSize,那么数组之中不存在目标值,
此时直接返回0,不再进行第二次查找;

在这里插入图片描述

代码:

int Binearch(int *nums,int numsSize,int target)//封装一个右边界二分查找
{
    int left=0;
    int right=numsSize-1;
    while(left<=right)
    {
        int mid=left+(right-left)/2;
        if(target<nums[mid])
        right=mid-1;
        else if(target>nums[mid])
        left=mid+1;
       else//找到了
       left=mid+1;
    }
    return left;//返回右边界点
}

int search(int* nums, int numsSize, int target){
   int R_right=Binearch(nums,numsSize,target);//找到第一个右边界点
  if(R_right<=0&&R_right>=numsSize)//数组中没有目标值
  return 0;
  int L_right=Binearch(nums,numsSize,(target-1));//找到target-1的边界
  return (R_right-L_right);

}

第三题

题目:
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
链接: link.
思路分析:
在这里插入图片描述
代码:

int missingNumber(int* nums, int numsSize){
    int left=0;
    int right=numsSize-1;
    while(left<=right)
    {
        int mid=left+(right-left)/2;
        if(nums[mid]==mid)//左边是有序
        left=mid+1;
        else//左边是无序的
        right=mid-1;
    }
    return left;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值