leetcode 153. 寻找旋转排序数组中的最小值 中等

已知一个长度为 n 的数组,预先按照升序排列,经由 1n旋转 后,得到输入数组。例如,原数组 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) 的算法解决此问题。

示例 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 次得到输入数组。

示例 3:

复制代码
输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示:

  • n == nums.length
  • 1 <= n <= 5000
  • -5000 <= nums[i] <= 5000
  • nums 中的所有整数 互不相同
  • nums 原来是一个升序排序的数组,并进行了 1n 次旋转

分析:原数组是一个升序排列的数组,进行旋转后,可能有两种情况:

1、旋转次数是原数组长度的倍数。此时旋转完仍然保持整体升序。

2、旋转次数不是原数组长度的倍数。此时旋转之后会出现两个部分,分别保持升序,且前半部分的最小值一定大于后半部分的最大值,以及存在一个分界位置,该位置左边的值大于右边的值。

由于不知道旋转次数,只能从找到分界位置入手。由于左右两边都是升序的,可以直接遍历数组,找到非升序的位置。但题目要求时间复杂度为 log(n),因此必须使用二分查找加快遍历速度。 每次取中间位置 mid,判断 mid 附近是否已经出现了旋转分界点。如果出现,则可以直接返回最小值;否则根据 numsmid 和当前区间左右端点的大小关系,判断最小值位于左半部分还是右半部分。

如果满足:numsmid > numsmid + 1,说明 mid 正好是前半段的最后一个位置,mid + 1 就是旋转后的最小值。

如果满足:numsmid < numsmid - 1,说明 mid 本身就是后半段的第一个位置,也就是最小值。

如果当前区间已经是整体升序的,即中间元素大于左端点、小于右端点,则说明当前区间没有发生断裂,最小值就是左端点。

否则,需要继续缩小搜索区间。当:numsmid > numsl,说明 mid 位于左侧较大的升序段中,最小值不可能在 lmid 之间,因此令:l = mid + 1

当:numsmid < numsr - 1,说明 mid 位于右侧较小的升序段中,最小值可能就是 mid,也可能在它左边,因此令:r = mid。

cpp 复制代码
class Solution {
public:
    int findMin(vector<int>& nums) {
        int l=0,r=nums.size(),mid;
        if(r==2)return min(nums[0],nums[1]);

        while(l<r)
        {
            mid=(l+r)/2;

            if(mid+1==r)return min(nums[l],nums[mid]);
            if(mid==l)return nums[mid];
            
            if(nums[mid]>nums[mid+1])return nums[mid+1];
            else if(nums[mid]<nums[mid-1])return nums[mid];
            else if(nums[mid]>nums[l]&&nums[mid]<nums[r-1])return nums[l];

            if(nums[mid]>nums[l])l=mid+1;
            else if(nums[mid]<nums[r-1])r=mid;
        }
        return 0;
    }
};
相关推荐
yyds_yyd_1008611 小时前
1464. 数组中两元素的最大乘积(2026.07.27)
数据结构·c++·算法·leetcode
玖玥拾14 小时前
LeetCode 26 删除有序数组中的重复项
算法·leetcode
白白白小纯16 小时前
算法篇—返回倒数第k个节点
c语言·数据结构·算法·leetcode
退休倒计时16 小时前
【复习】LeetCode 二叉树DFS TypeScript
算法·leetcode·typescript·深度优先
白白白小纯18 小时前
算法篇—链表的中间节点
c语言·数据结构·算法·leetcode
Frostnova丶18 小时前
(19)LeetCode 54. 螺旋矩阵
算法·leetcode·矩阵
Frostnova丶18 小时前
(18)LeetCode 73. 矩阵置零
算法·leetcode·矩阵
番茄撒旦在上19 小时前
LeetCode 98.验证二叉搜索树-Medium
算法·leetcode
rannn_11119 小时前
【力扣hot100】哈希表专题——从两数之和到最长连续序列
java·算法·leetcode·哈希
go不是csgo20 小时前
从模板到五道 LeetCode:完全背包的 Golang 教学笔记
笔记·leetcode·golang