704. 二分查找
给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
中心思想:找到中间值,跟中间值比较,如果比中间的大,就在后半部分;如果比中间的小,就在前半部分;如果相等即为所求。当遍历到最后,还不存在,则说明不存在。
方法一:左闭右闭区间( right=nums.size()-1;)
target 是在一个在左闭右闭的区间里,也就是[left, right] ,在这个情况下,while要包含left==right的情况。
class Solution {
public:int search(vector<int>& nums, int target) {int left=0;int right=nums.size()-1;if(right<left) return -1;while(left<=right){int mid=(right+left)/2;if(nums[mid]==target) return mid; else if(nums[mid]<target) left=mid+1;else right=mid-1; }return -1;}
};
方法二:左闭右开区间( right=nums.size();)
- while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
- if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
class Solution {
public:int search(vector<int>& nums, int target) {int left=0;int right=nums.size();if(right<=left) return -1;while(left<right){int mid=(right+left)/2;if(nums[mid]==target) return mid; else if(nums[mid]<target) left=mid+1;else right=mid; }return -1;}
};
374. 猜数字大小
这道题读懂题目即可。其实和上面一模一样
需要注意:
1 <= n <= - 1
- 2n其实超出了int的范围,所以需要把left、right、mid设置为long 类型
class Solution {
public:int guessNumber(int n) {//左闭右闭区间long left=1;long right=n;long mid;while(left<=right){mid=(left+right)/2;if(guess(mid)>0)// pick > numleft=mid+1;else if(guess(mid)==0) break;else right=mid-1;}return mid;}
};
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置.
时间复杂度为 O(log n)
的算法。-----》二分算法
返回按顺序插入的位置,其实就是二分查找的时候,left所在的点。
class Solution {
public:int searchInsert(vector<int>& nums, int target) {//if(target<nums[0]) return 0;int mid; int left=0;int right=nums.size()-1;while(left<=right){mid=(left+right)/2;if(nums[mid]>target) right=mid-1;else if((nums[mid]<target)) left=mid+1;else return mid;}return left;}
};
34. 在排序数组中查找元素的第一个和最后一个位置
两个方法:简单点想其实就是找到所有与target相等的值,最小的就是第一个,最大的就是最后一个。全部找出来,复杂度有点高。
方法一:那不妨想,第一个实际上就是不断向前找;最后一个就是不断向前找。可以分为两次查找
class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {if(!nums.size()) return {-1,-1};int first=-1;int last=-1;int mid;int left=0;int right=nums.size()-1;//找firstwhile(left<=right){mid=(left+right)/2;if(nums[mid]==target) {first=mid;right=mid-1;//不断向前找}else if(nums[mid]>target) right=mid-1;else left=mid+1;}//找lastleft=0; right=nums.size()-1;while(left<=right){mid=(left+right)/2;if(nums[mid]==target) {last=mid;left=mid+1;//不断向后找}else if(nums[mid]>target) right=mid-1;else left=mid+1;}return {first,last};}
};
方法二:看上面的代码,其实大部分代码都是相同的逻辑,我们不防精简一下:
class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {int l = 0, r = nums.size() - 1;vector<int> ret {-1, -1};while(l <= r){int mid = (l + r) / 2;if(nums[mid] > target){r = mid - 1;}else if (nums[mid] < target){l = mid + 1;}else{l = r = mid;while(--l >= 0 && nums[l] == target){;}while(++r < nums.size() &&nums[r] == target){;}ret[0] = l + 1;ret[1] = r - 1;return ret;}}return ret;}
};
这个就是找到中间那个相等的值之后,不断像前,向后逼近。(一次二分)
while(--l >= 0 && nums[l] == target){;}while(++r < nums.size() &&nums[r] == target){;}ret[0] = l + 1;ret[1] = r - 1;
167. 两数之和 II - 输入有序数组
双指针+空间缩减(题解推荐:167. 两数之和 II - 输入有序数组 - 力扣(LeetCode))
同样这里注意审题,返回的下标
class Solution {
public:vector<int> twoSum(vector<int>& numbers, int target) {//双指针+缩减空间int row=0;int col=numbers.size()-1;while(row<col){int sum=numbers[row]+numbers[col];if(sum>target){col--;}else if(sum<target) row++;else return vector<int>{row+1,col+1};}return vector<int>{-1,-1};}
};
拓展一下:返回二维数组的情况还可以直接返回
{row+1,col+1};
或者利用veror动态数组的内置函数
vector<int> res;res.push_back(low+1);res.push_back(high+1);return res;