二分查找
查找也是有特殊情况的,需要在有序数组中查找的时候,这时候二分查找(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;
}
};