第一类 需要查找和目标值完全相等的数
法一
int find(vector<int>& nums, int target) {
int left = 0, right = nums.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else right = mid;
}
return -1;
}
法二
int find(vector<int>& nums, int target) {
int left = 0, right = nums.size()-1;
while (left <= right) {
int mid = left + (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()因为不会取到这个值。并且当left==right的时候,可取left但不能取right但是这两个数又是同一个数,已经构成了矛盾。在判断mid并非属于合法区间后,新的区间可以update为[left, mid)。
相同的,法二可以理解为取的合法区间是左闭右闭[ , ]。nums.size()不属于合法区间所以right只可以取到nums.size()-1。当left==right,我们仍需要判断[left, left/right]中是否有target。在判断mid并非属于合法区间后,新的区间可以update为[left, mid-1]。
需熟悉掌握人工run这些code,之前面试遇到,我就慌乱了~
第二类 查找第一个不小于目标值的数,可变形为查找最后一个小于目标值的数
int find(vector<int>& nums, int target) {
int left = 0, right = nums.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) left = mid + 1;
else right = mid;
}
return right;
}
第三类 查找第一个不大于目标值的数,可变形为查找最后一个大于目标值的数
int find(vector<int>& nums, int target) {
int left = 0, right = nums.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] <= target) left = mid + 1;
else right = mid;
}
return right;
}
Reference: