文章目录
前言
很久没有写LeetCode题了……因为最近是考试周,必须得在LeetCode和考试中做一个抉择了。
前两天考完了两科,马原和数电,接下来的都是和计算机相关性很大的,所以复习的压力不是特别大了。
今天在复习算法的时候,看到了旋转数组问题,以前写过,现在又忘了,就通过LeetCode把这一类问题都写完了罢……
首先通过刷一类题,我发现LeetCode的难度值得吐槽,为什么呢,点了这几题的超链接你就知道了……
二分法的基本模板如下:
while (l < r) {
int m = l + r >> 1;
if (check(m)) r = m;
else l = m + 1;
}
通过这个模板最终你可以得到r==l,但[r]不一定是你想要的值,接下来你还要做一个判断,具体的看后面。
1. 寻找旋转排序数组中的最小值
1.1 二分
把右端点作为二段性的判断依据:
class Solution {
public:
int findMin(vector<int>& numbers) {
int l = 0;
int r = numbers.size() - 1;
while (l < r) {
int m = l + r >> 1;
if (numbers[m] <= numbers.back()) r = m;
else l = m + 1;
}
return numbers[l];
}
};
2. 寻找旋转排序数组中的最小值 II
2.1 二分
有可能有重复的数字,会破坏第一问的二段性,所以需要进行预处理,使得l要大于右端点:
class Solution {
public:
int findMin(vector<int>& numbers) {
int l = 0;
int r = numbers.size() - 1;
while (l < numbers.size() - 1 && numbers[l] == numbers[r]) l++;
while (l < r) {
int m = l + r >> 1;
if (numbers[m] <= numbers.back()) r = m;
else l = m + 1;
}
return numbers[l];
}
};
3. 搜索旋转数组
3.1 二分
根据前两问可以将这个问题转换为有序数组的搜索,注意的细节是需要返回最小的那个索引,有可能我们搜出来的结果是左端点,这时候加一句判断target是否等于左端点:
class Solution {
public:
int search(vector<int>& numbers, int target) {
int l = 0;
int r = numbers.size() - 1;
while (l < numbers.size() - 1 && numbers[l] == numbers[r]) l++;
while (l < r) {
int m = l + r >> 1;
if (numbers[m] <= numbers.back()) r = m;
else l = m + 1;
}
if (target <= numbers.back()) r = numbers.size() - 1;
else {
l = 0;
r--;
}
while (l < r) {
int m = l + r >> 1;
if (numbers[m] >= target) r = m;
else l = m + 1;
}
if (target != numbers[l]) return -1;
if (target == numbers[0]) return 0;
while (l > 0 && (numbers[l - 1] == numbers[l])) {
l--;
}
return l;
}
};
总结
通过三道题目强化学了下二分的思想……