题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路: 首先,要明白非递减数组的意思,是增+平,比如:1,2,3,3,4 (开始我真的没懂orz)
有序的数组排序:二分法。设头尾分别为 i , j 。 记搬到末尾的数组段为右排序数组,其余的为左排序数组。则左排序数组大于等于右排序数组。那么:
- 如果中间值大于 j 位置的值,说明中间值在左排序数组,最小值在它的右边,此时将 i = mid + 1;
- 如果中间值小于 j 位置的值,说明中间值在右排序数组,最小值在它的左边,此时 j = mid;
- 当中间值等于 j 时,无法判断在哪一段。解决方案: 执行 j = j - 1 缩小判断范围。
当 i = j 时跳出二分循环,并返回 numbers[i] 即可。
Q1: 为什么不跟 i 比较?
跟 i 比较时,若 mid 比 i 位置的值大,我们认为 mid 在左排序数组;比 i 位置的值小时,我们认为它在右排序数组。但如果是这种极端的情况:[1,2,3,4,5](即所有数组都搬到末尾,相当于没有动) 它应该是在右排序数组才对。
无论如何旋转,j 初始值肯定是在右排序数组,而 i 初始值是不确定在哪一段的。【像上述全部移动了的情况,就没有左排序数组了,也就是说,最左边的值可能是移动了的数组(右排序数组),也可能是未移动的(左排序数组)】
Q2: 为什么中间值等于 j 时执行 j = j - 1
首先, 无法判定 m 在左(右)排序数组:
- 例 [1, 0, 1, 1, 1] :旋转点 x = 1 ,因此 m = 2 在 右排序数组 中。
- 例 [1, 1, 1, 0, 1] :旋转点 x = 3 ,因此 m = 2 在 左排序数组 中。
其次, j = j - 1 操作的正确性证明: 只需证明每次执行此操作后,旋转点 x 仍在 [i, j] 区间内即可。
- 若 m 在右排序数组中: 也就是说[m,j]这段都是重复相同的值,那么 j = j - 1操作也就是减去了一个重复的值,最小值还是会在这个区间里面。
- 若 m 在左排序数组中: 由于 左排序数组 任一元素 >= 右排序数组 任一元素 ,因此可推出旋转点元素值 numbers[x] <= numbers[j] == numbers[m],则有:
- 若 numbers[x] < numbers[j] : 即 j 左方仍有值更小的元素,执行 j = j - 1 后旋转点 x 仍在 [i, j] 区间内。
- 若 numbers[x] == numbers[j] : 分为以下两种情况。
- 当 j>x : 易得执行 j = j - 1后旋转点 xx 仍在 [i, j] 区间内。
- 当 j=x: 特殊情况,即执行 j = j - 1 后旋转点 x 可能不在 [i, j] 区间内。例如 [1, 1, 1, 2, 3, 1],当 i = 0, m = 2=2 , j = 5 时执行 j = j - 1 后虽然 丢失了旋转点索引 x = 5 ,但最终返回值仍正确,这是因为:之后的二分循环一直在执行 j = m ,而区间 [i, m] 内的元素值一定都等于旋转点值 numbers[x] ( ∵ 区间内元素值既要满足 ≥ 也要满足 ≤ numbers[x]) ,因此 仍可保证正确的返回值 。
// 这里有点绕…我理解是,这种情况下中间值右边的数字都是等于旋转点的值的(也就是最小值),虽然j = j - 1 操作会丢失旋转点,但执行下去,j会往左移动,最终还是会返回最小值。
while(line=readline()){
let arr = JSON.parse(line);
print(minNumberInRotateArray(arr));
}
function minNumberInRotateArray(rotateArray)
{
// write code here
if (rotateArray.length === 0)return 0;
var i = 0, j = rotateArray.length - 1;
while(i < j){
var mid = Math.floor((i+j)/2);
if(rotateArray[mid] < rotateArray[j]) {
j = mid ;
}
else if(rotateArray[mid] > rotateArray[j]) {
i = mid + 1;
}
else j -= 1;
}
return rotateArray[i];
}
运行时间:17ms,占用内存:7396k