剑指offer10_旋转数组的最小数字

旋转数组的最小数字


把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

输入一个升序的数组的一个旋转,输出旋转数组的最小元素。

例如数组 {3,4,5,1,2}为 {1,2,3,4,5} 的一个旋转,该数组的最小值为 1。

数组可能包含重复项。

注意:数组内所含元素非负,若数组大小为 0,请返回 −1。

数据范围

数组长度 [0,90]。

样例
输入:nums = [2, 2, 2, 0, 1]

输出:0

题解
  1. 预处理
    首先处理数组末尾与首元素相同的元素,以消除末尾水平段对二分查找的影响。例如,数组 [3,3,1,3] 处理后会变为 [3,3,1]
  2. 完全单调判断
    若处理后的数组满足 nums[end] >= nums[0],说明数组未被旋转或已完全单调,直接返回首元素。
  3. 二分查找
    二分查找的目标是找到旋转点(即最小值的位置)。根据以下条件调整边界:
    • nums[mid] < nums[0],说明 mid 位于右半段(旋转后的较小部分),将右边界设为 mid
    • 否则,将左边界设为 mid + 1
复杂度分析
  • 时间复杂度
    • 预处理阶段最坏需要遍历整个数组(例如所有元素相同),时间复杂度为 O ( n ) O(n) O(n)
    • 二分查找的时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)
    • 总时间复杂度为 O ( n ) O(n) O(n)
  • 空间复杂度
    仅使用常数空间,复杂度为 O ( 1 ) O(1) O(1)
class Solution {
public:
    int findMin(vector<int>& nums) {
        int n = nums.size() - 1;
        if (n < 0) return -1; // 处理空数组
        // 删除末尾与首元素相同的元素
        while (n > 0 && nums[n] == nums[0]) n--;
        // 若数组完全单调,直接返回首元素
        if (nums[n] >= nums[0]) return nums[0];
        // 二分查找最小值
        int l = 0, r = n;
        while (l < r) {
            int mid = (l + r) >> 1; // 等价于 (l + r) / 2
            if (nums[mid] < nums[0]) r = mid;
            else l = mid + 1;
        }
        return nums[r];
    }
};
代码解释
  1. 预处理
    通过 while 循环删除末尾与首元素相同的元素,例如 [3,3,1,3] 变为 [3,3,1]
  2. 完全单调判断
    若处理后的数组满足 nums[end] >= nums[0](例如 [1,2,3,4]),说明未被旋转,直接返回首元素。
  3. 二分查找
    • 循环条件l < r 确保区间最终收敛到单个元素。
    • 中间值计算mid = (l + r) >> 1 取中间位置。
    • 边界调整:若 nums[mid] < nums[0],说明最小值在左半段(包含 mid),否则在右半段(mid + 1 开始)。
    • 返回值:最终 r 指向最小值的位置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值