LeetCode算法笔记-三道简单题题帮18万人探索二分查找区间的开与闭
大家好,我是给自己写知识笔记都要做标题党,精通标题党技巧,却依然骗不到评论关注的假讲师。
704题:(题目描述、示例、提示在此不再给出。)
先读题,数组是升序数组,且数组中的所有元素都不重复。我们不用担心二分查找的目标元素不唯一的问题。这都是使用二分法的条件。
二分查找的边界条件比较多,所及即使二分法逻辑比较简单,也总是“一写就废”。主要因为我们容易对区间的定义混淆。
左闭右闭区间和左闭右开区间的两种解法都是对于寻找一个数字的基本的二分搜索,只有区间选择的区别:
左闭右闭区间:
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}
}
左闭右开区间:
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length;
while (left < right) {
int mid = left + ((right - left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid;
}
return -1;
}
}
避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算。我们可以在函数体内加上如下代码提高效率,这些小细节在项目开发中挺重要的:
if (target < nums[0] || target > nums[nums.length - 1])
{
return -1;
}
278题:
1 <= bad <= n <= 2^31 - 1
提示数字很大,我们要忍一下。
依然是简单的二分法,但是数组越界处理方面有一点点小细节:
int mid = left + ((right - left)>>1);
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int left = 0;
int right = n-1;
while(left <= right){
int mid = left + ((right - left)>>1);
if(isBadVersion(mid)){
right = mid -1;
}else{
left = mid +1;
}
}
return left;
}
}
35题
本题的思路也没有很大的变化,依然是基本二分。但是对于返回值有要求有点变化。
- 如果找到匹配的元素,返回元素下标,即mid;此步骤没变
- 如果没有找到,则要返回能插入的元素下标,此处是重点。
这种情况根据我们的区间选择不同,返回值也正好相反。
我们只看mid,如果在左闭右闭区间内,返回值应该是mid+1;如果在左闭右开区间内,返回值应该是mid。
但是mid是在while循环中定义的变量,无法在while外return。
那我们就要找和上面结论相等的值:左闭右闭区间内:mid + 1 == left == right +2;左闭右开区间内:mid == right + 1 == left - 1
找到本质联系之后,本题就迎刃而解了:
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + ((right - left) >> 2);
if(nums[mid] == target)
return mid;
else if(nums[mid] > target)
right = mid - 1;
else if(nums[mid] < target)
left = mid + 1;
}
return left;
}
}
总结
- 注意边界,是左闭右闭区间还是左闭右开区间;
- 越界处理需要一点点细节,具体是什么还想的起来吗?
- 返回值有要求时,需要在意数据之间的联系,与区间联系到一起考虑。
|