一起刷算法 # 二分查找 # No.1
题目
153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode) (leetcode-cn.com)
用时
39分钟
结果

优化过程
第一次提交未通过,发现问题是因为对于 3 1 2这种,最小值刚好是mid的情况,无法正确寻找,因为它会跳过mid值。
这个时候我还没意识到,这是因为这道题不是标准二分法的原因,而我使用了一般二分的一般形式。
class Solution {
public int findMin(int[] nums) {
int low = 0, hi = nums.length - 1;
if(nums[low] < nums[hi])return nums[low];
if(nums.length == 2)return nums[0] > nums[1]? nums[1]:nums[0];
int mid = -1;
while(low <= hi){
mid = low + (hi - low) / 2;
System.out.println(mid);
if(nums[mid] > nums[0]){
low = mid + 1;
}
else{
hi = mid - 1;
}
}
return nums[mid];
}
}
第二次提交,这个时候我加入了一个判断条件
if(nums[mid] < nums[low] && nums[mid] < nums[hi])return nums[mid];
来处理这种mid是最小值的情况,但还是会有新的问题,这个时候我尝试继续加限制条件,但感觉不太对,这算法看起来就太复杂了。于是开始思考为什么不行。
class Solution {
public int findMin(int[] nums) {
int low = 0, hi = nums.length - 1;
if(nums[low] < nums[hi])return nums[low];
if(nums.length == 2)return nums[0] > nums[1]? nums[1]:nums[0];
int mid = -1;
int temp = -1;
while(low <= hi){
mid = low + (hi - low) / 2;
//System.out.print(mid);
//System.out.print(low);
//System.out.println(hi);
if(nums[mid] < nums[low] && nums[mid] < nums[hi])return nums[mid];
if(nums[low] < nums[hi])return nums[low];
if(nums[mid] > nums[low]){
low = mid + 1;
}
else{
hi = mid - 1;
}
temp = mid;
}
return nums[mid];
}
}
我发现,所有这些问题都是因为mid这个值在遍历时被漏掉了!
简单好理解的二分法!
要找这种序列的最小值,只需要思考,最小值到底在哪里? 最小值一定在无序部分中。
这些序列大概可以分为两种情况:
1. 前半部分有序:5 6 7 8/ 9 1 2
2. 后半部分有序:7 8 1 2/ 3 4 5
我们发现,最小值一定在无序部分,那么我们只需要不断寻找无序部分就行了
代码如下,这里有一些问题:
1.如何寻找无序部分?
通过if(nums[mid] >= nums[low]) 这一句比较来寻找,即中间值和每次二分出来的部分的第一个值比较,这一点比较好理解.
还需要加上这一句if(nums[low] <= nums[hi])return nums[low];表示剩下的序列全都是有序了,没法再找无序部分,这个时候直接返回第一个值即是最小值。
2.为什么hi = mid 而不是 mid - 1
在一般二分中,我们可以写mid - 1和mid + 1是因为我们有一句if(nums[mid] == target)break;**即每次我们都check到了mid位置的值,所以我们可以通过位置移动来排除这个值,但这个算法里是没有这句break语句check到mid值的,所以不能-1
于是最终版为:
class Solution {
public int findMin(int[] nums) {
int low = 0, hi = nums.length - 1;
if(nums[low] <= nums[hi])return nums[low];
int mid = -1;
while(low <= hi){
mid = low + (hi - low) / 2;
if(nums[low] <= nums[hi])return nums[low];
if(nums[mid] >= nums[low]){
low = mid + 1;
}
else{
hi = mid; //!!!!!!!!!!!这里不能减去1
}
}
return nums[mid];
}
}

浙公网安备 33010602011771号