LeetCode154-寻找旋转排序数组中的最小值II

题目链接

英文链接:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/

中文链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/

题目详述

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

请找出其中最小的元素。

注意数组中可能存在重复的元素。

示例 1:

1
2
输入: [1,3,5]
输出: 1

示例 2:

1
2
输入: [2,2,2,0,1]
输出: 0

说明:

题目详解

”数组 + 有序“可以联想到二分查找。本题是 LeetCode153-寻找旋转排序数组中的最小值 的加强版。因为数组中可能存在重复的元素,可能存在 [10,1,10,10,10] 这种极端情况。在这种情况下,算法必须退化到线性时间复杂度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class LeetCode_00154 {

public int findMin(int[] nums) {
return findMin(nums, 0, nums.length - 1);
}

private int findMin(int[] nums, int lo, int hi) {
// 只有一个元素或区间 [lo, hi] 已经有序
if (lo == hi || nums[lo] < nums[hi]) {
return nums[lo];
}
int mid = lo + (hi - lo) / 2;
return Math.min(findMin(nums, lo, mid), findMin(nums, mid + 1, hi));
}
}

另外,可以采用缩小存在区间的方法来得到最小值。

  • 最小值下标的范围为 [0, nums.length - 1]。在二分查找过程中,不断缩小范围,直至只有一个区间元素,即为所求。
  • 当 nums[mid] < nums[hi] 时,说明取值区间不可能在 [mid + 1, hi],令 hi = mid。
  • 当 nums[mid] > nums[hi] 时,说明取值区间不可能在 [lo, mid],令 lo = mid + 1。
  • 当 nums[mid] = nums[hi] 时,要么 nums[mid] 和 nums[hi] 均为最小值,要么 nums[mid] 和 nums[hi] 均不为最小值。可令 hi 自减,因为若 nums[mid] 和 nums[hi] 均为最小值,跳过 nums[hi] 这个最小值,还有 nums[mid] 这个最小值,对结果不会有影响;若 nums[mid] 和 nums[hi] 均不为最小值,显然可以跳过 nums[hi]。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class LeetCode_00154 {

public int findMin(int[] nums) {
int lo = 0;
int hi = nums.length - 1;
// 最小值的范围在 [0, nums.length - 1] 中。lo == hi 时,lo 就是最小值所在处。
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (nums[mid] < nums[hi]) {
hi = mid;
} else if (nums[mid] > nums[hi]) {
lo = mid + 1;
} else {
--hi;
}
}
return nums[lo];
}
}

可以在 LeetCode153-寻找旋转排序数组中的最小值 的基础上,删掉数组末尾与开头相等的部分,使二分查找具备有界性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class LeetCode_00154 {

public int findMin(int[] nums) {
int l = 0, r = nums.length - 1;
// 删掉末尾与开头相等的部分
while (l < r && nums[r] == nums[l]) {
--r;
}
while (l < r) {
int mid = l + r >>> 1;
if (nums[mid] <= nums[r]) r = mid;
else l = mid + 1;
}
return nums[r];
}
}