704. 二分查找
二分查找的两种典型写法(左闭右闭 左闭右开):
个人喜欢用的写法
我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right] (这个很重要非常重要)。
区间的定义这就决定了二分法的代码应该如何写,因为定义target在[left, right]区间,所以有如下两点:
- while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
- if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
对左闭右开的理解:
如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同。
有如下两点:
- while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
- if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
二分法的两道练习题:
35.搜索插入位置
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = 0,r = nums.size()-1;
while(l<=r){
int mid = l+((r-l)>>2);
int num = nums[mid];
if(num == target)return mid;
else if(target < num)r = mid-1;
else l = mid + 1;
}
return l;
}
};
其实上面更简化应该是将第一个判断去掉,这是我一开始练二分的时候并没有这么写,所以可以看下面35题查找元素在数组中第一个位置的代码。直接return l, 这个 l 既可以指没查找到元素的情况下他应该被顺序插入的位置,也可以指找到的情况下元素的下标。
左闭右开方法也是返回l,模拟如下:
34. 在排序数组中查找元素的第一个和最后一个位置
class Solution {
int binarysearch(vector<int>& nums, int target){
int l=0,r=nums.size()-1;
while(l<=r){
int mid = l + ((r-l)>>2);
int num = nums[mid];
if(target>num) l = mid + 1;
else r = mid - 1;
}
return l;
}
public:
vector<int> searchRange(vector<int>& nums, int target) {
int start = binarysearch(nums,target);
if((start == nums.size()) || (nums[start] != target))
return {-1,-1};
int end = binarysearch(nums,target+1)-1;
return {start,end};
}
};
这里对二分法的思想不做赘述,如果找到start, 必然有end, 这时候一个很巧妙的方法就是找target+1 的值,返回他前面的数下标。
27. 移除元素
双指针法 是本题的精髓,今日需要掌握 ,拓展题目我还没看。题目链接: . - 力扣(LeetCode)
这个一开始我没有用双指针思想,用的是remove方法,因为这个对vector容器进行元素的删除不改变size和capacity,也是非常简单的做法
C++ std::vector删除元素的几种方式及区别_stdvector删除元素-CSDN博客
代码如下:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int cnt = 0;
for(int num : nums){
if(num != val)cnt++;
}
remove(nums.begin(),nums.end(),val);
return res;
}
};
看到了题解评论区一个人的双指针解答非常有意思,(收藏版,帮助理解)
int removeElement(int* nums, int numsSize, int val) {
int slow = 0, fast = 0; //一对夫妇,原本都是零起点
while (fast < numsSize) { //但是有一个跑得快,一个跑得慢
if (nums[fast] != val) { //于是跑得快的那个先去寻找共同目标
nums[slow] = nums[fast]; //如果找到了,就送给跑得慢的那个
slow++; //然后跑得慢的那个也就离目标近一点
}
fast++; //但是不管是否找得到,跑得快的那方都一直奔跑到生命的尽头
}
return slow; //最终留下跑得慢的一方
}
977.有序数组的平方
题目建议 : 本题关键在于理解双指针思想
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
vector<int> ans(n);
for(int i =0,j=n-1,pos=n-1;i<=j;)//循环条件是i<=j的原因可以用假设法,i一直++,j不变,那么可以执行n次,那就对了。
{
if(nums[i]*nums[i]>nums[j]*nums[j]){
ans[pos]=nums[i]*nums[i];
i++;
}
else{
ans[pos]=nums[j]*nums[j];
j--;
}
--pos;
}
return ans;
}
};
这题的模拟如下:
就是从左边和右边进行比较,胜者进预先安排好的pos。
第一次记录博客,如有不足,各位大佬可在评论区指出!
明天继续 ❀❀❀