题目链接
代码随想录文章讲解链接
二分查找,设置左右边界,根据中间位置元素与目标元素的大小关系改变查找范围,右边界有意义
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = (right - left) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
};
二分查找,右边界无意义
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while (left < right) {
int mid = (right - left) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
} else {
return mid;
}
}
return -1;
}
};
一开始只想到左闭右闭的写法,看完讲解后学习到左闭右开的方法。
关键在于右区间是否有意义:
左闭右闭的右边界是位于搜索范围内的,while的判断条件是<=,且右边界的更新是等于中间索引;
左闭右开的右边界是位于搜索范围外的,while的判断条件是<,且右边界的更新是等于中间索引减一
无
题目链接
代码随想录文章讲解链接
二分查找
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = (right - left) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
return mid;
}
}
return left;
}
};
二分查找
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while (left < right) {
int mid = (right - left) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
} else {
return mid;
}
}
return left;
}
};
无
无
题目链接
代码随想录文章讲解链接
二分查找结合暴力解法,非标准解法,是一开始自己想到的做法。
使用二分查找找到某一个目标值的位置,然后从该位置向两侧分别寻找第一个目标元素的位置和最后一个目标元素的位置。
但是当数组全为同一元素时,这种方法的时间复杂度就会退化成 O ( n ) O(n) O(n),因为每个数字都要遍历一遍。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int size = nums.size();
int left = 0;
int right = size - 1;
if (right != -1) {
while (left <= right) {
int mid = (right - left) / 2 + left;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
right = mid;
left = mid;
while (right + 1 < size && nums[right + 1] == nums[mid]) {
++right;
}
while (left - 1 > -1 && nums[left - 1] == nums[mid]) {
--left;
}
return {left, right};
}
}
}
return {-1, -1};
}
};
定义左边界为小于目标值的元素最右边的位置,若超出范围数组范围则为-2。
例如数组[1,3,5,7]对于目标0和8的左边界为-2(-2超出1~7的范围),对于1的左边界为-1,对于5的左边界为1。
定义右边界为大于目标值的元素最左边的位置,若超出范围数组范围则为-2。
例如数组[1,3,5,7]对于目标0和8的右边界为-2(-2超出1~7的范围),对于5的右边界为3,对于7的右边界为4。
此处定义的左右边界都不包括目标数字本身。
使用两次二分查找,第一次二分查找寻找左边界的位置,若结果为-2,则说明目标值不在数组范围之中,直接返回[-1,-1];否则,进行第二次二分查找,寻找右边界的位置。
如果目标值是一个位于数组范围内的数,但是是数组中不存在的数,查找到的左右边界会是相邻的值,例如[1,3,5,7]查找目标4的左右边界,结果是1和2,这种情况也是返回[-1,-1]。
否则,左边界+1的位置即为目标数字的第一个位置,右边界-1的位置即为目标数字的最后一个位置。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = leftBorder(nums, target);
if (left == -2) {
return {-1, -1};
} else {
int right = rightBorder(nums, target);
if (right - left > 1) {
return {left + 1, right - 1};
}
return {-1, -1};
}
}
private:
int leftBorder(vector<int>& nums, int target) {
// 寻找左边界(不包含目标值)
int left = 0;
int right = nums.size() - 1;
int boarder = -2;
while (left <= right) {
int mid = (right - left) / 2 + left;
//若中间的值比目标值大或者相等,那么左边界一定在中间的值的左边部分
if (nums[mid] >= target) {
right = mid - 1;
boarder = right;
} else {
left = mid + 1;
}
}
return boarder;
}
int rightBorder(vector<int>& nums, int target) {
// 寻找右边界(不包含目标值)
int left = 0;
int right = nums.size() - 1;
int boarder = -2;
while (left <= right) {
int mid = (right - left) / 2 + left;
//若中间的值比目标值小或者相等,那么右边界一定在中间的值的右边部分
if (nums[mid] <= target) {
left = mid + 1;
boarder = left;
} else {
right = mid - 1;
}
}
return boarder;
}
};
25届毕业生对这严峻的就业环境开始焦虑,今天是开始刷代码随想录的第一天,也是小白刚开始尝试写博客,感觉写博客真的能提升对问题的理解,把思路理清楚。希望能早日一刷完且能坚持写博客,猪扒加油加油~