LeetCode 153: 寻找旋转排序数组中的最小值

题目描述


1.题目分析

数组可以按旋转点为分界线分为左右两部分,如:

[4,5,6,0,1,2,3] = [4,5,6] + [0,1,2,3]
数组A:[4,5,6]; 数组B:[0,1,2,3]
· 注意本题为各不相同
于是我们便可以分两种情况讨论:** ①mid指在数组A,②mid指在数组B。**

1.1 情况①:

	       A                  B
		[4,     5,     6] + [0,1,2,3]
		 ↑      ↑                  ↑
		left   mid                right

mid在数组A,则nums[mid] >= nums[left]。出现这种情况,便让left = mid + 1,因为最小值一定在B中,这样可以缩小左边范围。

1.2 情况②:

         A                B
		[4,5,6] + [0,   1,    2,   3]
		 ↑              ↑          ↑
		left           mid       right

mid在数组A,则nums[mid] < nums[left]。出现这种情况,便让right = mid, 之所以不是mid + 1, 是因为mid 可能就指向最小值,让right = mid就不会错过这种情况。


2. 我的尝试

2.1 错误尝试1 (边界溢出):

class Solution {
    public int findMin(int[] nums) {
        int left = 0, right = nums.length - 1;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] >= nums[left]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return nums[left];   
    }
}

2.1.1 报错信息:

索引超出边界

2.1.2 为什么会索引异常呢?

答:代码中left = mid + 1, 导致right = mid后,继续left继续右移了一位,导致边界异常。


2.2 错误尝试2 while (left < right):

class Solution {
    public int findMin(int[] nums) {
        int left = 0, right = nums.length - 1;
        while(left < right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] >= nums[left]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return nums[left];   
    }
}

那我们不要让left = right后跳出循环 ,是否能解决边界溢出呢?

2.2.2 结果错误
结果全为最右边的值

2.2.3 为什么还是不对呢?

原来当left跑到B中后,我们的选择条件便不再成立, 如:

              A                   B
		[4,     5,     6] + [0,   1,    2,    3]
		                     ↑    ↑           ↑
		                    left  mid        right

于是left会不断右移,导致最后输出的都是最右边的值。

2.2.4 如何解决呢?

出现这个问题的根本原因是nums[left]跑到B中去了,导致一直都只能进入如下的选择语句

	if (nums[mid] >= nums[left]) {
	                left = mid + 1;
	}

由于本题是为了找最小值,而最小值一定在B中,所以right指针一定不会跑到A里面去。如果拿nums[right]作为比较依据,便可以避免这种情况。


3. 代码实现

class Solution {
    public int findMin(int[] nums) {
        int left = 0, right = nums.length -1;

        while(left < right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] < nums[right]) {
                right = mid; // 不是mid - 1是防止 mid已经指向最小的 从而错过最小值
            } else{
                left = mid + 1;
            }
        }
        return nums[left];      
    }
}

4. 思考

为什么这里不是while(left <= right) 呢?

答:因为我们返回的是nums[left]。若循环条件为while(left <= right),则跳出循环时,left = right = mid,都指向最小值,而这时候还得进行最后一次循环,使left = mid + 1。这时,left便跑到mid和right右边一位去了,因此若要用while(left <= right)条件必须返回 nums[right] 或者 nums[left - 1]。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值