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


数组特点:

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

例如:

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

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

假设遇到 numsmid > numsleft 这个情况:

  • 场景 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 的右边。
    - 结论:同样的条件 numsmid > numsleft,最小值可能在左,也可能在右。算法无法做出决策。

这题中,我们不是找目标值,是找最小值,即:答案是有的,不需要返回 -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

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

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


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

  1. 内部必须有 if numsmid == 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。此时这个重合的点就是唯一没有被排除掉的点。
相关推荐
小欣加油6 小时前
leetcode56 合并区间
c++·算法·leetcode·职场和发展
8Qi810 小时前
LeetCode 516:最长回文子序列
算法·leetcode·职场和发展·动态规划
小欣加油14 小时前
leetcode287寻找重复数
数据结构·c++·算法·leetcode
怪兽学LLM15 小时前
LeetCode 438 找到字符串中所有字母异位词(Python 固定滑动窗口+字符计数解法)
python·算法·leetcode
Tisfy16 小时前
LeetCode 3689.最大子数组总值 I:What The Medium
算法·leetcode·题解·贪心·模拟·脑筋急转弯
moeyui70517 小时前
LeetCode 380:Insert Delete GetRandom O(1) 题解和一些延伸
算法·leetcode·职场和发展
圣保罗的大教堂17 小时前
leetcode 3689. 最大子数组总值 I 中等
leetcode
退休倒计时17 小时前
【每日一题】LeetCode 15. 三数之和 TypeScript
数据结构·算法·leetcode·typescript
小欣加油18 小时前
leetcode3689最大子数组总值I
c++·算法·leetcode·职场和发展·贪心算法
人道领域19 小时前
【LeetCode刷题日记】90.子集Ⅱ--- 归纳题解
java·开发语言·leetcode