package com.heu.wsq.leetcode.binarysearch;
/**
* 153. 寻找旋转排序数组中的最小值
* @author wsq
* @date 2021/4/9
* 已知一个长度为 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 ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
*
* 示例 1:
* 输入:nums = [3,4,5,1,2]
* 输出:1
* 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
*
* 示例 2:
* 输入:nums = [4,5,6,7,0,1,2]
* 输出:0
* 解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组
*
* 链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array
*/
public class FindMin {
/**
* 二分查找,由于左右两部分都是有序的,因此每次可以通过区间中点值使得区间缩小一半
* 1. 当区间中心元素值大于左边界left对应的元素值,则当前的最小值肯定是left对应的元素值,然后还有可能在mid右边出现更小的值,
* 因此使得left = mid + 1去在右边的区间继续搜索。
* 2. 当区间中心元素值小于左边left对应的元素值,则当前的最小值为mid对应的元素值,然后还可能在mid左边出现更小的元素值,因此
* 使得right = mid - 1,去mid的左边的区间继续搜索。
* @param nums
* @return
*/
public int findMin(int[] nums) {
int n = nums.length;
if(n == 1){
return nums[0];
}
int left = 0;
int right = n-1;
int ans = Integer.MAX_VALUE;
// 如果该题目中存在,则需要单独的判读去解决含有重复元素的问题,不然走下面的逻辑可能会找错最小值的方向
if(nums[mid] == nums[left] && nums[right] == nums[mid]){
ans = Math.min(ans, nums[mid]);
left++;
right--;
continue;
}
while(left <= right){
int mid = (left + right) >> 1;
if(nums[mid] >= nums[left]){
// 如果mid值大于左边界值,证明,目前处于递增序列,最小值出现在右边,此时的最小值为左边界值
ans = Math.min(ans, nums[left]);
left = mid + 1;
}else{
// 如果mid值小于左边界值,证明,目前mid处于第二个递增序列,最小值肯定在left和mid中间,此时的最小值为mid对应的元素值
right = mid - 1;
ans = Math.min(ans, nums[mid]);
}
}
return ans;
}
}