二分查找(折半查找)

本文介绍了二分查找在有序数组和矩阵场景中的应用,包括查找最小值的方法和在特定矩阵结构中的优化策略。通过实例演示了如何利用二分查找技巧解决'kthSmallest'问题,并结合'check'函数实现高效搜索。
摘要由CSDN通过智能技术生成

二分查找

查找也是有特殊情况的,需要在有序数组中查找的时候,这时候二分查找(Binary search)就派上用场了。

二分查找的原理与实现

升序数组
以一个升序数组为例,将数组从中间一分为二,分为左右两个部分。
在这里插入图片描述
将待查找的值target与中间值比较,会出现以下三种情况:

  • 中间值正好与target值相等,那就太好了,我们一下子就找到了。
  • 中间值比target值大,说明我们要查找的值在左半边,那么在左半边再次二分查找。
  • 中间值比target值小,说明我们要查找的值在右半边,那么在右半边再次二分查找。

示例

![在这里插入图片描述](https://img-blog.csdnimg.cn/517229c847584e3fbbafd41b1634ad6c.png
在这里插入图片描述
思路
以mid为界,将数组分成左右两部分,比较一下nums[mid]和nums[right]的值,如果大的话,说明我们应该去mid的左边去找最小值,否则去右边。
代码:

class Solution {
public:
    int findMin(vector<int>& nums) {
        //大胆试一试
        //找最小值
        int n=nums.size();
        int left=0,right=n-1;
        int min_value=0x3f3f3f;
        while(left<right)
        {
          int mid=(left+right)/2;
          //说明在左边边会出现最小值,去左半边找
          if(nums[mid]<nums[right])
          {
            right=mid;
          }
          else
          {
            left=mid+1;
          }
        }
        return nums[left];
    }
};

在这里插入图片描述** 思路**
这道题给我的第一反应就是二分查找,因为行是升序的,列也是升序的,但是卡在了怎么去实现,看了题解后,才恍然大悟。
对于下面这样一个数组,列升序,行也升序,所以左上角应该是数组的最小值,右上角是数组的最大值,定义一个mid代表数组的中间值,我们运用二分查找去寻找小于mid的值个数,

  • 如果小于mid的值少于k个的话,说明目标值target应该小于mid;
  • 如果小于mid的值多于k个的话,说明目标值target应该大于mid;

在这里插入图片描述

class Solution {
public:
    bool check(vector<vector<int>>&matrix,int n,int mid,int k)
    {
      int i=n-1;
      int j=0,num=0;
      while(i>=0 && j<n)
      {
        if(matrix[i][j]<=mid)
        {
            /*如果当前值小于mid,因为行是升序的,
            那么当前位置水平上的所有值都大于mid*/
            num+=i+1; 
            //因为列也是升序的,
            j++;
        }
        else{
          i--;
        }
      }
      return num>=k;
    }
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int row=matrix.size(),colum=matrix[0].size();
        int left=matrix[0][0],right=matrix[row-1][row-1];
        while(left<right)
        {
          int mid=(left+right)/2;
          if(check(matrix,row,mid,k))
          {
            //说明目标值应该小于mid
            right=mid;
          }
          else{
            //目标值大于mid
            left=mid+1;
          }
        }
        return left;//为什么return的是left
    }
};

在这里插入图片描述

class Solution {
public:
     vector<vector<int>>twoSum(vector<int>& nums, int target,int left,int right,int value)
    {
      vector<vector<int>>answer;
      while(left<right)
      {
        int sum=nums[left]+nums[right];
        if(sum==target)
        {
          vector<int>result;
          result.push_back(value);
          result.push_back(nums[left]);
          result.push_back(nums[right]);
          //result[[value,left,rigth]]
          answer.push_back(result);
          //跳过重复的数字
          while(left<right &&nums[left]==nums[left+1])
            left++;
          while(left<right&&nums[right]==nums[right-1])
            right--;
          left++;
          right--;
        }
        else if(sum>target)
          right--;
        else if(sum<target)
          left++;
      }
      return answer;
    }
    vector<vector<int>> threeSum(vector<int>& nums) {
      vector<vector<int>>answer;
      int n=nums.size();
      //先排序
      sort(nums.begin(),nums.end());
      //枚举a的过程,跳过重复值
      for(int i=0;i<n;i++)
      {
        if(i>0&&nums[i]==nums[i-1])
        {
          continue;
        }
        //二分法查找b和c;
        auto result=twoSum(nums,-nums[i],i+1,n-1,nums[i]);
        //在answer的尾部插入新的数据
        answer.insert(answer.end(),result.begin(),result.end());
      }
      return answer;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值