Suppose an array of length n
sorted in ascending order is rotated between 1
and n
times. For example, the array nums = [0,1,2,4,5,6,7]
might become:
[4,5,6,7,0,1,2]
if it was rotated4
times.[0,1,2,4,5,6,7]
if it was rotated7
times.
Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]]
1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]]
.
Given the sorted rotated array nums
, return the minimum element of this array.
Example 1:
Input: nums = [3,4,5,1,2] Output: 1 Explanation: The original array was [1,2,3,4,5] rotated 3 times.
Example 2:
Input: nums = [4,5,6,7,0,1,2] Output: 0 Explanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times.
Example 3:
Input: nums = [11,13,15,17] Output: 11 Explanation: The original array was [11,13,15,17] and it was rotated 4 times.
Constraints:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
- All the integers of
nums
are unique. nums
is sorted and rotated between1
andn
times.
寻找旋转有序数组的最小值。影子题154。
思路还是用二分法做。这道题我选择使用 while (start + 1 < end) 这个模板,这样我最后需要额外判断 nums[start] 和nums[end],但是因为是找最小值而不是找目标值所以这个模板我个人觉得做起来比较方便。
因为数组是旋转过的所以数组的最大值很有可能在中间,所以需要这样判断
- 如果mid小于end,说明mid - end是一段递增,直接就end = mid了,因为最小值一定在mid左侧
- 如果mid大于end,说明start - mid是一段递增,最小值在mid右侧,start = mid
时间O(logn)
空间O(1)
JavaScript实现
1 /** 2 * @param {number[]} nums 3 * @return {number} 4 */ 5 var findMin = function(nums) { 6 let start = 0; 7 let end = nums.length - 1; 8 while (start + 1 < end) { 9 let mid = Math.floor(start + (end - start) / 2); 10 if (nums[mid] < nums[end]) { 11 end = mid; 12 } else { 13 start = mid; 14 } 15 } 16 if (nums[start] < nums[end]) return nums[start]; 17 else return nums[end]; 18 };
这里稍微解释一下while循环里面的if条件判断。第十行,如果nums[mid] < nums[end],就说明后半段一定是升序的,没有被rotate过的,所以end = mid;同理可以得到如果nums[mid] >= nums[end],那么没有被rotate过的部分一定在前半段,所以start = mid。跳出while循环的时候说明没找到,但是此刻start和end满足如下关系,left < target < right, left + 1 = right,所以有最后的判断。
Java实现
1 class Solution { 2 public int findMin(int[] nums) { 3 int start = 0; 4 int end = nums.length - 1; 5 // start + 1 < end 6 // 举例,start - 0, end = 3 7 // 中间隔了起码有start + 1和start + 2两个下标 8 // 这样跳出while循环的时候,end < start 9 // 才有了最后的两个特判 10 while (start + 1 < end) { 11 int mid = start + (end - start) / 2; 12 if (nums[mid] < nums[end]) { 13 end = mid; 14 } else { 15 start = mid; 16 } 17 } 18 if (nums[start] < nums[end]) { 19 return nums[start]; 20 } else { 21 return nums[end]; 22 } 23 } 24 }