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

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

题目链接:34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

题目分析

题目:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 -1, -1。 核心:分别二分查找左边界、右边界。左边界是第一个等于 target 的位置;右边界是最后一个等于 target 的位置。 边界注意:找到边界后,要校验边界是否合法、对应数值是否等于 target,防止 target 不存在。

算法原理

两次二分:

  1. 找左边界:nums[mid] >= target 收缩右边界
  2. 找右边界:nums[mid] <= target 收缩左边界,最后结果 - 1 才是最后一个 target 位置 拿到左右边界后必须校验,数组里没有 target 时返回 -1,-1

代码编写

cpp 复制代码
vector<int> searchRange(vector<int>& nums, int target) {
    int n = nums.size();
    int left = 0, right = n;
    // 找左边界
    while(left < right) {
        int mid = left + (right - left) / 2;
        if(nums[mid] >= target) right = mid;
        else left = mid + 1;
    }
    int l = left;
    // 找右边界
    left = 0, right = n;
    while(left < right) {
        int mid = left + (right - left) / 2;
        if(nums[mid] <= target) left = mid + 1;
        else right = mid;
    }
    int r = left - 1;
    if(l < n && nums[l] == target) return {l, r};
    return {-1, -1};
}

总结

重复有序数组专用,两次边界二分;校验是必写步骤,很多人漏这一步导致报错。


第二题:33. 搜索旋转排序数组

题目链接:33. 搜索旋转排序数组 - 力扣(LeetCode)

题目分析

题目:整数数组 nums 按升序排列,数组中的值互不相同。在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了旋转,使数组变为 nums \[k, nums k+1, ..., nums n-1, nums 0, nums 1, ..., nums k-1]。给你旋转后的数组 nums 和一个整数 target,如果 nums 中存在这个目标值,则返回它的下标,否则返回 -1。 核心:旋转数组一定有一半区间是有序的。判断左半段有序还是右半段有序,再看 target 是否落在有序区间内,以此收缩二分边界。

算法原理

旋转数组二段性:左右两段必有一段有序

  1. 判断左半段是否有序 nums[left] <= nums[mid]
    • 有序且 target 落在这个区间:去左边搜
    • 否则去右边搜
  2. 右半段有序
    • 有序且 target 落在这个区间:去右边搜
    • 否则去左边搜

代码编写

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

总结

旋转数组二分重点:先识别有序区间,再判断 target 是否在有序区间内,是面试高频题。

相关推荐
2601_967979121 小时前
机器学习必修课:经典算法与Python实战
python·算法·机器学习·实战·课程
程序猿打工仔1 小时前
计算机基础(C语言)考编、专技岗
c语言·开发语言·算法
通信小呆呆2 小时前
电子战干扰技术:从“蛮力压制”到“精准欺骗”,再到“认知博弈”
算法·通信·isac
老师我太想进步了20262 小时前
【数据结构-6】算法美学之单链表(1)
数据结构·算法
希望我万事顺遂3 小时前
力扣hot100-滑动窗口最大值
数据结构·算法·leetcode
꧁细听勿语情꧂3 小时前
二叉树余题,排序、直接插入排序、希尔排序
c语言·开发语言·数据结构·算法
是main不是漫4 小时前
【双指针|LeetCode1089 复写零】巧用逆向思路,破解原地覆盖陷阱
数据结构·算法·leetcode
专注仿真13 小时前
知识问答模型用到的算法集详解及代码实例
python·算法·代码·大模型训练·控制算法
罗西的思考14 小时前
【轻量化复刻大模型 / KIMI K3】AttnRes 模块交互式演示
人工智能·算法·机器学习
好悬给我拽开线18 小时前
ZILOT 论文解析
算法