旋转数组的最小数字
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
要求:空间复杂度:O(1)O(1) ,时间复杂度:O(logn)O(logn)
示例1:
输入:[3,4,5,1,2]
返回: 1
示例2:
输入:[3,100,200,3]
返回: 3
解题思路
暴力解法可以挨个遍历数组,寻找最小值,但是子题目要求:空间复杂度:O(1)O(1) ,时间复杂度:O(logn)O(logn),这就需要用一些技巧了
首先旋转数组将原本有序的数组分成了两部分有序的数组,因为在原始有序数组中,最小的元素一定是在首位,旋转后无序的点就是最小的数字。旋转后我们可以把数组分为AB两个区域,可以知道A区域所有的值都大于B区域
用两个指针,分别指向最左侧left和最右侧right,再获取一个中间指针mid;以区间[left,right]的最右侧的值为基准,使中间值与它比较;慢慢缩小区域,当left大于等于right时,就找到了最小值
具体步骤如下:
- 第一步:初始化左右指针,双指针指向旋转后数组的首尾,作为区间端点。
- 第二步:当左指针小于右指针则进入循环
- 计算获取中间指针
- 若是区间中点值小于区间右界值,则最小的数字一定在中点左边。
right = mid
- 若是区间中点值大于区间右界值,则最小的数字一定在中点右边。
left = mid+1
- 若是区间中点值等于区间右界值,则是不容易分辨最小数字在哪半个区间,应该逐个缩减右界令
right--
- 第三步:当left大于等于right时,就找到了最小值,返回
rotateArray[left]
function minNumberInRotateArray(rotateArray){ let left = 0 let right = rotateArray.length-1; while(left < right){ let mid = Math.floor( (left + right)/2 ); if(rotateArray[mid] < rotateArray[right]){ right = mid; }else if(rotateArray[mid] > rotateArray[right]){ left = mid+1; }else{ right--; } } return rotateArray[left]; }