LeetCode 704. 二分查找
难度:简单
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size(); // 差异点1
int mid = left + (right - left) / 2;
while(left < right) { // 差异点2
mid = left + (right - left) / 2;
if(nums[mid] == target) {
return mid;
} else if(nums[mid] < target) {
left = mid + 1;
} else {
right = mid; // 差异点3
}
}
return -1;
}
};
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1; // 差异点1
int mid = left + (right - left) / 2;
while(left <= right) { // 差异点2
mid = left + (right - left) / 2;
if(nums[mid] == target) {
return mid;
} else if(nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1; // 差异点3
}
}
return -1;
}
};
关键点理解
理解二分查找两种写法的差异性的关键在于:
- 判断mid下标的元素是否在下一个待搜索区间内
- 循环什么时候终止,即判断区间内什么时候没有可供判断的元素
1. 判断mid下标的元素是否在下一个搜索区间内
已知如果nums[mid] != target,那么mid不应该出现在下一个搜索区间中
在左闭右开的区间中,即[left, right)区间中,left位置在区间内,right不在,所以如果是left位置需要修改,那么应该是left=mid+1(如果left=mid,就会导致mid下标对应的数出现在下一个搜索区间内;如果是right位置需要修改,那么就可以是right=mid;
在左闭右闭的区间中,即[left, right]区间中,left位置在区间内,right也在,那么此时如果right位置需要修改,就必须变为right = mid - 1,以保证nums[mid]不会出现在下一个搜索区间中
2. 循环什么时候终止,即判断区间内什么时候没有可供判断的元素
难点是什么时候可以等于,什么时候不能等于(其他简单,不讨论了)
在左闭右开的区间中,即[left, right)区间中,如果left==right,此时nums[left](nums[right])不在区间中,所以此时区间中没有元素,循环不应该继续,所以循环进行的条件是while(left > right)
在左闭右闭的区间中,即[left, right]区间中,如果left==right,此时nums[left](nums[right])在区间中,此时区间中还有需要判断的元素,循环应该继续,所以循环进行的条件是while(left >= right)
LeetCode 27.移除元素
难度:简单
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0, fast = 0;
while(fast != nums.size()) {
if(nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
}
};
关键点理解
关键点在于理解快指针和慢指针分别是做什么的
简洁地说,快指针负责搜索,慢指针负责记录。快指针搜索整个数组,不符合的元素就跳过,而每确定一个符合要求的元素,就告诉慢指针,慢指针将其记录下来,同时慢指针移向下一个记录点位。
如果感觉难以理解,可以想象出两个数组,慢指针在另一个数组上移动,而快指针将符合要求的元素拷贝过去,每拷贝一个元素,慢指针就向前移一格,所以慢指针同时也指示了数组中元素的个数
因为快指针永远不会落在慢指针后面,所以不用担心元素被覆盖,可以将两个数组合并,在同一数组上操作。