二分查找的两种写法
1.target (要搜寻的目标值)是在一个在左闭右闭的区间里,也就是[left, right]
- while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
- if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
2.target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同
- while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
- if (nums[middle] > target) right更新为middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 思路:
- 目标值在数组所有元素之前
- 目标值等于数组中某一个元素
- 目标值插入数组中的位置
- 目标值在数组所有元素之后
1. target 是在一个在左闭右闭的区间里
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n - 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 right + 1;
}
};
1. target 是在一个在左闭右开的区间里,也就是[left, right)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n;
while (left < right) {
int middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle;
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
return right;
}
};
在排序数组中查找元素的第一个和最后一个位置
力扣链接 有如下三种情况:
- 情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4,5},target为6,此时应该返回{-1, -1}
- 情况二:target在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1,-1}
- 情况三:target在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}
采用while (left <= right)的写法,区间定义为[left, right],即左闭右闭的区间 确定好:计算出来的右边界是不包含target的右边界,左边界同理。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
if (leftBorder == -2 || rightBorder == -2) return {-1, -1};
if (rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1};
return {-1, -1};
}
private:
int getRightBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int rightBorder = -2;
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
int getLeftBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int leftBorder = -2;
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] >= target) {
right = middle - 1;
leftBorder = right;
} else {
left = middle + 1;
}
}
return leftBorder;
}
};
|