153.寻找旋转排序数组中的最小值
153.Find Minimum in Rotated Sorted Array
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array
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 rotated 4 times.
[0,1,2,4,5,6,7] if it was rotated 7 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 of unique elements, return the minimum element of this array.
You must write an algorithm that runs in O(log n) time.
题目分析
如果不考虑时间复杂度该题最容想到的解法就是对数字进行排序,然后取最小值。但题目要求使用O(logn)的解法。所以我们不能遍历整个数组,需要采用二分的方法
线性表
二分查找
time defeat 100%
一、二分法
1.先考虑边界条件 数组度为1 直接返回第一个数,长度为2返回最小值
2. 由于题目的数组是具有一定过的有序。我们要找到最小值,只需要锁定 最小逆序的区域片段【Max,MIN】或者 特殊情况已经是完全有序的数组
性我们就分成以下三种情况
左半边逆序 nums[L] > nums[mid], 最小值肯定在左边,再进行折半 把范围缩短 R = mid
右半边逆序 nums[mid] >nums[R] 最小值肯定在右边,再进行折半,把范围缩短到 L = mid
左右均顺序 直接返回nums[0];
- 需要注意 : 右边折半的过程中 不用让L = mid+1;因为对于奇数的length{3,4,5,1,2},会丢失掉 逆序这个信息。无法找最小值
- 出循环的条件。就是得到最小的逆序区域时 L = R-1, L = mid时
- 此时返回 nums[R]就是最小的值。
class Solution {
public int findMin(int[] nums) {
if(nums.length <= 1) return nums[0];
if(nums.length == 2) return Math.min(nums[0],nums[1]);
int mid;
int L = 0;
int R = nums.length-1;
while(L< R){
mid = L+((R-L)>>1);
if(mid == L) break;
if(nums[L] > nums[mid]){
R = mid;
}else if(nums[mid] > nums[R]){
L = mid;
}else{
return nums[0];
}
}
return nums[R];
}
}
简化版
public static int findMin0(int[] nums) {
int L = 0;
int R = nums.length - 1;
// LR 重叠时break 数组元素不重复
while (L < R) {
int mid = L + ((R - L) >> 1);
if (nums[mid] < nums[R]) {
// 右半边 升序,最小值往左找,右边不要,缩小R范围
R = mid;
} else {
// 右边逆序,往右找,左边不要 缩小L范围
L = mid + 1;
}
}
return nums[L];
}
154. 寻找旋转排序数组中的最小值 II
154. Find Minimum in Rotated Sorted Array II
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,4]
若旋转 7 次,则可以得到 [0,1,4,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须尽可能减少整个过程的操作步骤。
链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii
Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,4,4,5,6,7] might become:
[4,5,6,7,0,1,4] if it was rotated 4 times.
[0,1,4,4,5,6,7] if it was rotated 7 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 that may contain duplicates, return the minimum element of this array.
You must decrease the overall operation steps as much as possible.
此题是153的兄弟题,题目没有规定必须采用O(logn)的解法。我只用遍历一次数组也可以 获取100% time defeat的结果
java 代码如下:在遍历过程中如果提前找最小值就break;
由于数组是有序的 只是包含重复元素。如果整体非有序的,最小值一定出现在前一个值比他的位置。
class Solution {
public int findMin(int[] nums) {
int min = nums[0];
for (int i = 1; i < nums.length ; i++) {
min = Math.min(min,nums[i]);
if(nums[i-1] > nums[i]) break;
}
return min;
}
}
二分方法
public int findMin2(int[] nums) {
int L = 0;
int R = nums.length - 1;
while (L < R) {
int mid = L + ((R - L)>>1);
if (nums[mid] < nums[R]) {
// 右边为升序,未出现逆序,最小值还在左边 缩小R的范围到mid
R = mid;
} else if (nums[mid] > nums[R]) {
//说明逆序在右边。左边不要,缩小左边的范围L = mid+1;
L = mid + 1;
} else {
// nums[L] == nums[R] 时, 不能忽略任何一边 单独移动试试
R--;
}
}
return nums[L];
}