leetcode-153/154

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];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值