leetcode hot100 153. 寻找旋转排序数组中的最小值 medium 二分查找


数组特点:

  1. 原本升序
  2. 旋转后变成两段升序
  3. 最小值就是 两段的分界点
  4. 最小值在无序的那半边

例如:

coffeescript 复制代码
[4,5,6,7,0,1,2]
           ↑
         最小值
  1. 情况 1:nums[mid] > nums[right]:说明 mid 到 right 这一段是无序的(被断开),右半边无序,最小值在右半边
  2. 情况 2:nums[mid] < nums[right]:说明 mid 到 right 这一段是升序的,右半边有序,最小值在左半边

为什么只能和右端点比较?

假设遇到 nums[mid] > nums[left] 这个情况:

  • 场景 A(无旋转/完全升序):[1, 2, 3, 4, 5] left=1, mid=3。此时 3>13 > 13>1,最小值在 mid 的左边
  • 场景 B(有旋转):[3, 4, 5, 1, 2] left=3, mid=5。此时 5>35 > 35>3,最小值在 mid 的右边。
    - 结论:同样的条件 nums[mid] > nums[left],最小值可能在左,也可能在右。算法无法做出决策。

这题中,我们不是找目标值,是找最小值,即:答案是有的,不需要返回 -1,只需要找到位置


coffeescript 复制代码
class Solution:
    def findMin(self, nums: List[int]) -> int:
        left = 0
        right = len(nums)-1

        ans = float("inf")  # 无穷大

  
        while left <= right:
            mid = (left + right) // 2
            
            # 没有target, 要找的是最小值,所以维护当前观察到的最小值
            if nums[mid] < ans:
                ans = nums[mid]
            
            if nums[mid] > nums[right]:  # 右边断层,在右边
                left = mid + 1
            elif nums[mid] < nums[right]:  # 右边连续,在左边
                right = mid - 1
            else:
                # nums[mid] == nums[right] ,此时结束循环
                return ans
                
        return ans

🚩 潜在的问题:else: return ans

在元素互不相同的前提下,nums[mid] == nums[right] 只有一种情况会发生:就是 mid == right。

由于 mid 是向下取整,mid == right 只会在 left == right 时发生。此时返回 ans 是正确的。但是,如果这道题稍微变一下,允许重复元素(比如 LeetCode 154 题) return ans 就会提前收工,导致错误。


while left <= right 时,当找到 nums[mid] == target 时返回mid坐标,找不到结束循环时,是left > right

  1. 内部必须有 if nums[mid] == target: return mid。
  2. 指针移动总是 left = mid + 1 和 right = mid - 1。
  3. 终局状态:如果循环是因为不满足条件而结束,此时 left > right(实际上此时 left = right + 1)
  4. 适用场景:在一个没有重复元素的有序数组中找一个具体的数

while left < right 时,当找到 nums[mid] == target 时,让循环继续,则结束循环时,是left == right

  1. 循环内部不直接返回,而是不断缩小 [left, right] 区间
  2. 指针移动通常是 left = mid + 1 和 right = mid
  3. 在 Python 中,mid = (left + right) // 2 是向下取整的。当区间只剩下两个元素(例如 left=0, right=1)时:mid = (0 + 1) // 2 = 0,此时 mid 永远等于 left。
  4. 如果写 right = mid - 1,就把这个潜在的正确答案彻底排除在搜索区间之外了。所以必须写 right = mid,确保正确答案依然留在 [left, right] 区间内。
  5. 终局状态:结束时 left == right。此时这个重合的点就是唯一没有被排除掉的点。
相关推荐
让我上个超影吧2 小时前
【力扣34】在排序数组中查找元素的第一个和最后一个位置
java·数据结构·算法·leetcode
We་ct2 小时前
LeetCode 103. 二叉树的锯齿形层序遍历:解题思路+代码详解
前端·算法·leetcode·typescript·广度优先
Swift社区2 小时前
LeetCode 391 完美矩形 - Swift 题解
算法·leetcode·swift
烟花落o2 小时前
【数据结构系列04】随机链表的复制、环形链表I、环形链表||
数据结构·算法·leetcode·链表
pursuit_csdn11 小时前
LeetCode 1022. Sum of Root To Leaf Binary Numbers
算法·leetcode·深度优先
踩坑记录13 小时前
leetcode hot100 35. 搜索插入位置 medium 二分查找
leetcode
-海绵东东-15 小时前
哈希表······················
算法·leetcode·散列表
菜鸡儿齐16 小时前
leetcode-全排列
算法·leetcode·深度优先
不想看见40416 小时前
Maximal Square 基本动态规划:二维--力扣101算法题解笔记
算法·leetcode·动态规划