剑指Offer 11. 旋转数组的最小数字

方法一:二分法

题设给的是一个原有序数组,通过旋转,将其变为两个递增的有序序列,且第一个序列递增——骤减——第二个序列递增。目标就是查找骤减(平行)处的位置。

三种情况:

mid < j  :  说明目标值一定在mid的左边且包括mid,使j = mid;

mid > j  :  说明此时的mid在原数组的右半部分,且此时处于旋转后的数组的左半部分,旋转点在其右方且不包括mid(因为已知mid > j ,所以要找的最小值点一定不是mid),所以使i = mid + 1

mid == j  :  不能确定此时为什么情况,j可能就是要找的最小值,因此使 j--,直到其退出循环或者mid != j时再做处理。

为什么不用m和i做比较?

二分目的是判断 mm 在哪个排序数组中,从而缩小区间。而在 nums[m] > nums[i]情况下,无法判断 m 在哪个排序数组中。本质上是由于 j 初始值肯定在右排序数组中; i 初始值无法确定在哪个排序数组中。举例如下:

对于以下两示例,当 i = 0, j = 4, m = 2 时,有 nums[m] > nums[i] ,而结果不同。
[1,2,3,4,5] 旋转点 x = 0 : m 在右排序数组(此示例只有右排序数组);
[3,4,5,1,2] 旋转点 x = 3 : m 在左排序数组。

 1 /**
 2  * @param {number[]} numbers
 3  * @return {number}
 4  */
 5 var minArray = function(numbers) {
 6     let left = 0, right = numbers.length - 1;
 7     while(left < right) {
 8         const mid = Math.floor((left + right) / 2);
 9         if(numbers[mid] > numbers[right]) {//mid > right说明mid处为原数组右半,最小值在mid右边
10             left = mid + 1;
11         }else if (numbers[mid] < numbers[right]) {// mid < right 说明target在mid的左边可能包括mid
12             right = mid;
13         }else {
14             right = right - 1;
15         }
16     }
17     return numbers[right];
18 };

 

posted @ 2021-09-08 15:59  雪之下。  阅读(44)  评论(0)    收藏  举报