提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
一个本硕双非的小菜鸡,备战24年秋招,计划刷完卡子哥的刷题计划,加油!
推荐一手卡子哥的刷题网站,感谢卡子哥。代码随想录
一、704.二分查找
力扣704二分查找
Time / Space:时间 32 ms,内存 27 MB
Note:对于target的边界问题要注意,要理解记忆。
以下是 target 在[left, right]中
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle - 1;
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
return -1;
}
};
二、35. 搜索插入位置
Time / Space:时间4 ms击败78.85%,内存9.4 MB击败30.30%
Note:官方题解下munpf大佬关于为何返回的是left解释的很好,以下是原回答:
不需要ans变量,最后直接返回left就可以了,根据if的判断条件,left左边的值一直保持小于target,right右边的值一直保持大于等于target,而且left最终一定等于right+1,这么一来,循环结束后,在left和right之间画一条竖线,恰好可以把数组分为两部分:left左边的部分和right右边的部分,而且left左边的部分全部小于target,并以right结尾;right右边的部分全部大于等于target,并以left为首。所以最终答案一定在left的位置。
以下是我的理解:匹配不到的倒数第二步会出现middle = left(此时left与right差值为1),执行left + 1,最终会出现left = right,然后执行right - 1.所以如果我们想要较大的那个位置,应该返回left。
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle - 1;
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
return left;
}
};
三、34. 在排序数组中查找元素的第一个和最后一个位置
Time / Space:时间16 ms,内存13.2 MB
Note:官方题解比较通俗易懂,说白了就是把二分查找当作一个函数来调用。
class Solution {
public:
int binarySearch(vector<int>& nums, int target, bool lower) {
int left = 0;
int right = nums.size() - 1;
int ans = nums.size();
while(left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target || (lower && nums[middle] >= target)) {
right = middle - 1;
ans = middle;
} else {
left = middle + 1;
}
}
return ans;
}
vector<int> searchRange(vector<int>& nums, int target) {
int leftIndex = binarySearch(nums, target, true);
int rightIndex = binarySearch(nums, target, false) - 1;
if(leftIndex <= rightIndex && rightIndex < nums.size() && nums[leftIndex] == target && nums[rightIndex] == target) {
return vector<int>{leftIndex, rightIndex};
}
return vector<int>{-1, -1};
}
};
四、367. 有效的完全平方数
Time / Space:时间4 ms击败25.44%,内存5.8 MB击败31.10%
Note:两个middle相乘会超过int,记着用long
class Solution {
public:
bool isPerfectSquare(int num) {
int leftIndex = 0;
int rightIndex = num;
while (leftIndex <= rightIndex) {
long middle = leftIndex + ((rightIndex - leftIndex) / 2);
if (middle * middle > num) {
rightIndex = middle - 1;
} else if (middle * middle < num) {
leftIndex = middle + 1;
} else {
return true;
}
}
return false;
}
};
总结
写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。