【算法拾光】二分查找|二分查找 + 再排序数组中查找元素的第一个和最后一个位置

标签:二分查找、左边界二分、右边界二分、LeetCode 704 / LeetCode 34 区间规范:统一使用 左闭右闭 left, right 写法,工程、面试最稳,减少边界 bug


一、LeetCode 704 二分查找704. 二分查找 - 力扣(LeetCode)

1. 题目分析

题目 :给定一个升序排列、无重复元素的整型数组 nums 和目标值 target。如果数组中存在目标值,返回它的下标;不存在则返回 -1。 已知条件 :数组有序、元素不重复 需求 :快速定位目标,不暴力遍历 暴力缺点:O (n),数据量大时很慢;二分可以做到 O (log n)

2. 算法原理(分步)

二分核心思想:有序数组可以不断折半,排除一半不可能的区间

  1. 定义查找区间 [left, right],左端点 left = 0,右端点 right = nums.size()-1
  2. 循环条件:left <= right(左闭右闭,区间有效才循环)
  3. 取中间下标 mid = left + (right - left) / 2,规避 left+right 溢出
  4. 比较 nums[mid] 和 target:
    • nums[mid] == target:找到目标,直接返回 mid
    • nums[mid] < target:目标在右边区间,更新 left = mid + 1(mid 已经比对过,不需要再包含)
    • nums[mid] > target:目标在左边区间,更新 right = mid - 1
  5. 循环结束,区间空了,说明不存在 target,返回 - 1

3. 代码编写

cpp 复制代码
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return -1;
    }
};

二、LeetCode 34 在排序数组中查找元素的第一个和最后一个位置34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

1. 题目分析

题目 :升序整型数组(允许元素重复),给目标值 target,找出目标在数组里第一次出现的下标 和 最后一次出现的下标 ;不存在返回 [-1, -1] 难点 :数组有重复!普通二分找到一个就退出,无法拿到左右边界。 举例 :nums = [5,7,7,8,8,10], target=8,答案是 [3,4] 需求拆解:

  • 子问题 1:二分找左边界:等于 target 的最靠左位置
  • 子问题 2:二分找右边界:等于 target 的最靠右位置

2. 算法原理(分步)

依然使用左闭右闭 left, right,和 704 保持一套逻辑,方便记忆

找左边界逻辑
  1. 初始化 left=0,right=nums.size()-1,答案 res=-1(默认不存在)
  2. 循环 left <= right
  3. 算出 mid,对比:
    • nums[mid] == target:先记录当前 mid 为候选答案 ,但不返回!继续向左搜索,尝试找更早出现的 target → right = mid - 1
    • nums[mid] < target:目标在右侧 → left = mid + 1
    • nums[mid] > target:目标在左侧 → right = mid - 1
  4. 循环结束,res 就是左边界,没找到维持 - 1
找右边界逻辑
  1. 初始化 left=0,right=nums.size()-1,答案 res=-1
  2. 循环 left <= right
  3. 算出 mid,对比:
    • nums[mid] == target:先记录当前 mid 为候选答案 ,不返回!继续向右搜索,尝试找更晚出现的 target → left = mid + 1
    • nums[mid] < target:目标在右侧 → left = mid + 1
    • nums[mid] > target:目标在左侧 → right = mid - 1
  4. 循环结束,res 就是右边界
主函数逻辑

分别调用获取左边界、右边界两个函数,组装成 vector 返回。

3. 代码编写

cpp 复制代码
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int leftBound = getLeftBound(nums, target);
        int rightBound = getRightBound(nums, target);
        return {leftBound, rightBound};
    }

    // 获取左边界:第一个等于target的下标
    int getLeftBound(vector<int>& nums, int target){
        int left = 0;
        int right = nums.size() - 1;
        int res = -1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] == target){
                res = mid;
                right = mid - 1;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return res;
    }

    // 获取右边界:最后一个等于target的下标
    int getRightBound(vector<int>& nums, int target){
        int left = 0;
        int right = nums.size() - 1;
        int res = -1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] == target){
                res = mid;
                left = mid + 1;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return res;
    }
};

三、两篇对比总结

表格

题目 数组特点 命中 target 行为 作用
704 普通二分 有序无重复 直接 return 判断是否存在,返回任意一个位置
34 边界二分 有序可重复 记录答案,继续向一侧压缩区间 找左 / 右边界

核心口诀:有序才能二分;普通二分找到就走,边界二分找到不松手,往一边挤!

相关推荐
武子康1 小时前
H3-World 为何在加载 LoRA 前,先检查导入的代码?
人工智能·深度学习·算法
秋天的怀念_David2 小时前
算法一千零一夜 · 第二十八夜 注册
java·程序人生·算法
Rain的Java大神之路4 小时前
LeetCode 37 解数独面试攻略:回溯 + 位掩码 + MRV,从暴力到毫秒级求解
java·后端·leetcode
NEFU_Jyj4 小时前
贝尔数(组合数学)
算法
希和20275 小时前
C语言程序设计题|有序数组插入数字冒泡排序
c语言·数据结构·算法
Pniubi5 小时前
力扣73 矩阵置零
算法·leetcode·矩阵
布莱克60515 小时前
C++ 中 map 的 insert 与 emplace:key 已存在时会覆盖吗?
开发语言·数据结构·c++·算法·map
D e re k ZH18 小时前
C++ 系统学习手记:从语法细节到工程实践
开发语言·数据结构·c++·算法
石小石Orz19 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法