每天五分钟:二分查找-LeetCode高频题解析_day4

34. 在排序数组中查找元素的第一个和最后一个位置

1)为什么要二分两次?

数组有序,二分能在 log n 时间定位"边界"。

我们想要的是:

  • left:target 第一次出现的位置(最左)

  • right:target 最后一次出现的位置(最右)

2)lower_bound 是什么?

lower_bound(x):返回 第一个 >= x 的下标。

比如 nums = [5,7,7,8,8,10]

  • lower_bound(8) = 3(第一个 >= 8 的位置就是 8 的第一个出现)

  • lower_bound(9) = 5(第一个 >= 9 的位置是 10)

3)怎么得到右边界?

右边界 = 最后一个 target 的位置。

如果我们能找到 lower_bound(target + 1):

  • 它是 第一个 >= target+1 的位置

  • 那它前一个位置 -1 一定是 最后一个 target(如果 target 存在)

所以:

  • right = lower_bound(target + 1) - 1

4)为什么要检查存在性?

有可能数组里根本没有 target。

例如 nums=1,2,4, target=3:

  • left = lower_bound(3) 会得到 2(指向 4)

  • 但 nums[left] != target,说明没找到,返回 [-1,-1]

python 复制代码
from typing import List

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        # 找到第一个 >= target 的位置(左边界)
        def lower_bound(x: int) -> int:
            l, r = 0, len(nums)  # 注意:右边用 len(nums),表示"开区间"
            while l < r:
                mid = (l + r) // 2
                if nums[mid] < x:
                    l = mid + 1
                else:
                    r = mid
            return l

        left = lower_bound(target)          # 第一个 >= target 的位置
        right = lower_bound(target + 1) - 1 # 第一个 >= target+1 的位置,再往左一步就是最后一个 target

        # 验证 target 是否真的存在
        if left == len(nums) or nums[left] != target:
            return [-1, -1]
        return [left, right]

162.寻找峰值

把数组看成一座"山路",每个数字是高度。

你站在中间 mid,只看右边一格:

  • 如果**nums[mid] < nums[mid+1]** :说明 右边更高 ,你正走在"上坡"

    👉 山顶一定在右边(继续往右找)

  • 否则**nums[mid] > nums[mid+1]** :说明 右边更低 ,你在"下坡或山顶附近"

    👉 山顶一定在左边(包含 mid)(继续往左找)

这就是二分的依据:只看坡度方向,就能保证峰值在那一侧。

python 复制代码
class Solution:
    def findPeakElement(self, nums) -> int:
        l, r = 0, len(nums) - 1

        while l < r:
            mid = (l + r) // 2
            if nums[mid] < nums[mid + 1]:
                # 右边更高:峰值在右侧
                l = mid + 1
            else:
                # 右边更低或持平:峰值在左侧(含 mid)
                r = mid

        return l

34. 在排序数组中查找元素的第一个和最后一个位置

python 复制代码
class Solution:
    def findMin(self, nums):
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[left] <= nums[mid]:
                # 左侧有序
                if nums[mid] <= nums[right]:
                    # 整个数组有序
                    return nums[left]
                else:
                    # 左有序右无序
                    left = mid + 1
            else:
                # 左侧无序
                if nums[mid] <= nums[right]:
                    # 左无序右有序
                    right = mid
                else:
                    # 理论上不会出现这个else块,因为正常情况下
                    # 左右两侧必有一侧为有序
                    pass
        return -1

解释:

初始化指针:

left 和 right 分别初始化为数组的左端和右端。

循环进行二分搜索:

计算当前中间位置的索引 mid。

判断左半部分是否有序:if numsleft <= numsmid。

如果左半部分有序,再进一步判断整个数组是否有序:if numsmid <= numsright。

如果是,则返回左端的值,numsleft。

否则,说明右半部分存在无序部分,所以将 left 更新为 mid + 1。

如果左半部分无序,则进一步判断右半部分是否有序:if numsmid <= numsright。

如果是,将 right 更新为 mid,因为最小值在左侧部分。

根据题意,不会进入到else块,因为存在旋转的情况下,左右两部分总有一部分是有序的。

返回结果:

如果在循环中找到了最小值,则返回最小值。

否则返回 -1(实际上不会达到这里,因为按照题意我们总能在循环里找到最小值)。

相关推荐
东莞市云毅网络有限公司4 小时前
AI 引用句逐条回指原文:让回答可回溯的校验实现
python·数据清洗·rag·企业知识库·文档解析
数字融合6 小时前
透明化视频三维矿山井下照明重建技术
人工智能·python·数码相机
yi0116 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
Marst Code7 小时前
上位机开发日记 · 第 2 篇 · 架构先行:六层分层与边界
python
李日华大战鸡红8 小时前
FOC状态空间方程模型推导(学习记录)
python·学习·线性代数
灯澜忆梦8 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下9 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J9 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛9 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有10 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode