LeetCode153中关于二分法查找的while循环条件问题(left < right 还是 left <= right)

1.题目

力扣153题,点击这里
参考题解,点击这里

2. 代码

代码 1 while (left < right)

    public int findMin1(int[] nums) {//输入的nums是不重复元素的数组。所以:mid = right 等价于 nums[mid] = nums[right]
        int left = 0;
        int right = nums.length - 1;              
        while (left < right) {                   // 循环条件判断,如果left == right,则循环结束 
            int mid = left + (right - left) / 2;    //地板除,mid更靠近left
            if (nums[mid] > nums[right]) {          //中值 > 右值,最小值在右半边,收缩左边界
                left = mid + 1;                     //因为中值 > 右值,中值肯定不是最小值,左边界可以跨过mid 
            } else if (nums[mid] < nums[right]) {   //明确中值 < 右值,最小值在左半边,收缩右边界 
                right = mid;                        //因为中值 < 右值,中值也可能是最小值,右边界只能取到mid处 
            }
        }
        return nums[left];    //循环结束,left == right,最小值输出nums[left]或nums[right]均可 
    }

代码 2 while (left <= right)

    public int findMin2(int[] nums) { //输入的nums是不重复元素的数组。所以:mid = right 等价于 nums[mid] = nums[right]
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        while (left <= right) {                         // 循环的条件选为左闭右闭区间left <= right
            mid = left + (right - left) / 2;
            if (nums[mid] >= nums[right]) {             // 注意是当中值大于等于右值时,
                left = mid + 1;                         // 将左边界移动到中值的右边
            } else if (nums[mid] < nums[right]){        // 当中值小于右值时
                right = mid;                            // 将右边界移动到中值处
            }
        }
        return nums[right];                             // 最小值返回nums[right]
    }

3. 分析

首先我们要考虑while循环条件是由什么决定的。显然,在二分法查找中,循环条件是由循环内部左右边界(left 和 right)的赋值决定的。并且不同的while循环条件下,最后return的结果也有所不同。
在分析代码之前,我们首先要明白mid是怎么得到的。由上述代码可知:

mid = left + (right - left) / 2;

因此,mid是由right和left经过地板除得到的中值索引,并且更靠近left(在right-left=1时,mid等于left)。了解这个是很重要的。

1.分析代码1

代码循环中的第一个条件判断是:

if (nums[mid] > nums[right])

这时根据题意,该条件下我们可知需要求的最小值一定在left的右边 (不包括left),故:

left = mid + 1; 

其实上述left的赋值操作,根据逻辑来看,即使不包括left,似乎也可以是:“left = mid;”。但是,由于mid是地板除,在right和left的区间范围一步步缩小到最后的时候不能够使得left等于right,会陷入死循环。

代码循环中的第二个条件判断是:

if (nums[mid] < nums[right])

这时根据题意,该条件下我们可知需要求的最小值一定在right的左边 (包括right),故:

right = mid;

因为mid是地板除得到的,所以“right = mid;”语句能够在right和left的区间范围一步步缩小到最后的时候使得right等于left
因而,基于上述赋值操作后,right和left相互靠近最终会相等的趋势来看,可以得出循环的结束条件是left == right,即while条件判断是while (left < right),并且最终返回的值为:

return nums[left];  

或者

return nums[right];  

这里返回不能是return nums[mid]; ,因为在循环内赋值的最后一步操作使得left = right,最后一步循环判断结束while循环,就不会再进入循环更新mid。

2.分析代码2

代码循环中的第一个条件判断是:

if (nums[mid] >= nums[right])

这个条件判断相较于代码1中多了 “=” 判断,这是为了使循环条件判断为:while (left <= right)。即,在left和right相等(相等时,left = mid = right)之后,再多执行一次“left = mid + 1; ”,使得left > right,最后跳出循环。并且最后的返回值为:

return nums[right];  

或者

return nums[mid];  

不能是 return nums[left] 是因为left在最后一步为了结束循环,已经大于right了。
除上述之外,其余原理 同代码1。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值