剑指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 };

#
浙公网安备 33010602011771号