题目

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).

Find the minimum element.

The array may contain duplicates.

Example 1:

  1. Input: [1,3,5]
  2. Output: 1

Example 2:

  1. Input: [2,2,2,0,1]
  2. Output: 0

Note:


题意

将一递增数列的随机后半部分与前半部分换位,得到新数组,在新数组中查找最小值(数组中有重复的值)。

思路

153. Find Minimum in Rotated Sorted Array (M)相比,允许数组中存在重复的值,这带来的问题是,很难根据一个元素与最左侧元素的大小关系来判断它是落在左区间还是右区间,如数组 [10, 10, 1, 10, 10, 10]。

因此在153. Find Minimum in Rotated Sorted Array (M)解法的基础上做出改动:只有当nums[mid]与nums[left]存在严格的大于小于关系时,才能确定mid是落在左区间还是右区间,而当nums[mid]等于nums[left]时,因为无法有效判断区间归属,只能令left右移(或者right左移)。在最坏情况下(全元素一样),时间复杂度退化至0154. Find Minimum in Rotated Sorted Array II (H) - 图1

也可以用分治法实现。


代码实现

Java

二分法

  1. class Solution {
  2. public int findMin(int[] nums) {
  3. int left = 0, right = nums.length - 1;
  4. while (left < right) {
  5. // 当前区间已经是有序区间,则最小值就是nums[left]
  6. if (nums[left] < nums[right]) {
  7. return nums[left];
  8. }
  9. int mid = left + (right - left) / 2;
  10. if (nums[mid] < nums[right]) {
  11. right = mid;
  12. } else if (nums[mid] > nums[right]) {
  13. left = mid + 1;
  14. } else {
  15. right--;
  16. }
  17. }
  18. return nums[right];
  19. }
  20. }

分治法

  1. class Solution {
  2. public int findMin(int[] nums) {
  3. return findMin(nums, 0, nums.length - 1);
  4. }
  5. private int findMin(int[] nums, int left, int right) {
  6. if (left == right) {
  7. return nums[left];
  8. }
  9. int mid = left + (right - left) / 2;
  10. return Math.min(findMin(nums, left, mid), findMin(nums, mid + 1, right));
  11. }
  12. }

JavaScript

二分法

  1. /**
  2. * @param {number[]} nums
  3. * @return {number}
  4. */
  5. var findMin = function (nums) {
  6. let left = 0, right = nums.length - 1
  7. while (left < right) {
  8. if (nums[left] < nums[right]) {
  9. return nums[left]
  10. }
  11. let mid = Math.trunc((right - left) / 2) + left
  12. if (nums[mid] < nums[left]) {
  13. right = mid
  14. } else if (nums[mid] > nums[left]) {
  15. left = mid + 1
  16. } else {
  17. left++
  18. }
  19. }
  20. return nums[left]
  21. }

分治法

  1. /**
  2. * @param {number[]} nums
  3. * @return {number}
  4. */
  5. var findMin = function (nums) {
  6. return dac(nums, 0, nums.length - 1)
  7. }
  8. let dac = function (nums, left, right) {
  9. if (left === right) {
  10. return nums[left]
  11. }
  12. let mid = Math.trunc((right - left) / 2) + left
  13. return Math.min(dac(nums, left, mid), dac(nums, mid + 1, right))
  14. }