寻找旋转排序数组中的最小值——简单明了的二分查找

问题背景

我们有一个经过旋转的升序数组,旋转意味着把数组的尾部元素移到前面,原数组的顺序被打乱。我们需要找到旋转后数组中的最小值,且要求时间复杂度为 O(log n),这提示我们应该使用二分查找来解决问题。

例如:

  • 输入:[3,4,5,1,2],原数组:[1,2,3,4,5],旋转了 3 次,最小值为 1。
  • 输入:[4,5,6,7,0,1,2],原数组:[0,1,2,4,5,6,7],旋转了 4 次,最小值为 0。

解题思路

旋转排序数组的最小值一定位于“数组被旋转的切点”处。通过二分查找,我们可以有效地定位这个切点。

二分查找的关键点:

  • 如果 nums[mid] 小于 nums[right],说明最小值位于左半边,右边界收缩。
  • 否则,最小值在右半边,左边界收缩。

代码实现

class Solution {
    public int findMin(int[] nums) {
        int n = nums.length;
        int left = 0, right = n - 1;  // 初始化左右边界
        
        while (left < right) {
            int mid = left + (right - left) / 2;  // 防止溢出的写法
            // 如果中间值小于右边界值,说明最小值可能在中间左侧
            if (nums[mid] < nums[right]) {
                right = mid;
            } else {
                // 否则最小值在右半部分
                left = mid + 1;
            }
        }
        
        return nums[left];  // left 和 right 会收敛到最小值位置
    }
}

代码解释

  1. 初始化边界: left = 0right = n - 1,这是整个数组的初始范围。
  2. 循环条件: 在每次循环中,我们判断 nums[mid] 是否小于 nums[right]。如果是,说明最小值位于左半边;否则,最小值在右半边。
  3. 更新边界: 根据条件更新左右边界,直到 leftright 相遇,最终定位到最小值的位置。

时间复杂度分析

  • 每次二分查找都会将搜索范围缩小一半,因此时间复杂度为 O(log n),满足题目要求。

边界条件处理

  • 特殊情况: 如果数组的长度为 1,直接返回该元素。
  • 没有旋转的情况: 如果数组没有旋转,最小值是数组的第一个元素。

进一步的优化与思考

通过此解法,我们利用了二分查找的特性,使得算法可以在 O(log n) 的时间复杂度内解决问题。这种方式相较于 O(n) 的暴力解法在性能上有了显著提升。

练习题

  1. 给定一个旋转排序数组,如何找到旋转的次数?
  2. 如果数组中的元素不是互不相同的,如何修改代码?

通过优化后的内容,文章不仅清晰简洁,而且更易于读者理解。同时,附加的练习题也能帮助读者进一步巩固所学的知识,提升他们的思考深度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值