当前位置: 首页 > news >正文

【LeetCode 热题 100】35. 搜索插入位置——二分查找(闭区间)

Problem: 35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(log N)
    • 空间复杂度:O(1)

整体思路

这段代码同样旨在解决 “搜索插入位置 (Search Insert Position)” 的问题。它也是基于二分查找(Binary Search),但采用了另一种常见的“左闭右闭”区间模板。这个模板的搜索逻辑和边界处理与“左闭右开”版本略有不同。

算法的整体思路可以分解为以下步骤:

  1. 定义搜索区间

    • 算法使用两个指针 leftright 来定义一个左闭右闭的搜索区间 [left, right]
    • left 初始化为 0,right 初始化为数组的最后一个索引 nums.length - 1。这意味着初始搜索范围覆盖了整个数组的所有合法索引。
  2. 循环搜索

    • 算法的主体是一个 while (left <= right) 循环。这个条件意味着只要搜索区间 [left, right] 还不是空的(即 left 没有越过 right),搜索就继续。当 left > right 时,区间为空,循环终止。
    • 在循环内部,计算中间位置 mid。这里使用了 mid = (right - left) / 2 + left 的写法,这是一种防止 left + right 整数溢出的标准做法。
    • 比较与分区:将中间位置的元素 nums[mid]target进行比较:
      • Case 1: nums[mid] < target: 如果中间值小于目标值,说明 target 必定在 mid 的右侧。因此,我们可以安全地排除掉 mid 及其左侧的所有元素。通过 left = mid + 1,将搜索区间更新为 [mid + 1, right]
      • Case 2: nums[mid] >= target: 如果中间值大于或等于目标值,说明 target 可能就是 nums[mid],或者在 mid 的左侧。在这种情况下,我们不能断定 target 不在 mid 的右侧,但可以确定答案一定不在 mid 的右侧。因此,通过 right = mid - 1,将搜索区间更新为 [left, mid - 1]
  3. 确定最终结果

    • 循环最终会因为 left 越过 rightleft = right + 1)而终止。
    • 此时 left 指针的位置具有一个非常重要的含义:它指向的是数组中第一个大于 target 的元素的位置(或者如果所有元素都小于等于 target,它会指向 nums.length)。
    • 为什么返回 left 是正确的?
      • target 存在:如果 target 存在,循环可能会在某一步找到 nums[mid] == target。在这种情况下,right 会变为 mid-1left 不变,下一轮循环 left 可能会继续右移。最终,left 会停在 target 的位置或其右侧。但由于题目是求插入位置,而这个版本的二分查找最终找到的是第一个大于target的位置,所以不完全匹配。但仔细分析循环结束时的状态:left 指针左边的所有元素都 < targetright 指针右边的所有元素都 >= target。当循环结束时,left = right + 1,所以left正好是分界点,即插入位置。
      • target 不存在left 会停在第一个比 target 大的元素的位置,这正是 target 应该插入的地方。
      • 所有元素都小于targetleft 会一直右移,最终变为 nums.length,这也是正确的插入位置。
      • 所有元素都大于targetright 会一直左移,最终变为 -1,而 left 保持为 0,这也是正确的插入位置。
    • 因此,直接返回 left 是该算法模板下的正确选择。

完整代码

class Solution {/*** 在一个已排序的数组中查找目标值,如果找到则返回其索引,* 否则返回它应该被插入的位置的索引。* @param nums 一个已升序排序的整数数组* @param target 目标整数* @return 目标值的索引或插入位置的索引*/public int searchInsert(int[] nums, int target) {// left: 搜索区间的左边界,初始为 0。int left = 0;// right: 搜索区间的右边界,初始为数组的最后一个索引。// 定义了一个左闭右闭的搜索区间 [left, right]。int right = nums.length - 1;// 当左边界小于或等于右边界时,搜索空间不为空,循环继续。// 循环终止条件是 left > right。while (left <= right) {// 计算中间索引。这种写法可以有效防止 (left + right) 导致的整数溢出。int mid = (right - left) / 2 + left;// 如果中间值小于目标值if (nums[mid] < target) {// 说明目标值必定在右半部分 [mid + 1, right] 中。// 更新左边界,排除 mid 及左边的所有元素。left = mid + 1;} else { // nums[mid] >= target// 说明目标值在左半部分 [left, mid - 1] 中,或者 target 就是 nums[mid]。// 更新右边界,排除 mid 及右边的所有元素。// 即使 nums[mid] == target,我们也继续向左搜索,试图找到更靠前的插入点。right = mid - 1;}}// 循环结束时,left > right。// left 指针的位置是第一个大于等于 target 的元素应该在的位置。// 这正是 target 的插入位置。return left;}
}

时空复杂度

时间复杂度:O(log N)

  1. 算法核心:该算法是二分查找。
  2. 计算依据
    • 与上一个版本类似,while 循环的每一次迭代都会将搜索区间 [left, right] 的大小(即 right - left + 1)大约减半。
    • 这导致循环的迭代次数与 N 的对数成正比。
    • 因此,时间复杂度为 O(log N)

空间复杂度:O(1)

  1. 主要存储开销:算法只使用了 left, right, mid 等几个固定的整型变量。
  2. 计算依据
    • 这些变量的数量不随输入数组 nums 的大小 N 变化。
    • 没有创建任何与输入规模成比例的额外数据结构。

综合分析
算法所需的额外辅助空间是常数级别的。因此,其空间复杂度为 O(1)

http://www.dtcms.com/a/302275.html

相关文章:

  • 区块链分叉原理与代码仿真
  • leetcode 2044. 统计按位或能得到最大值的子集数目 中等
  • 主要分布于内侧内嗅皮层的层Ⅲ的网格-速度联合细胞(Grid × Speed Conjunctive Cells)对NLP中的深层语义分析的积极影响和启示
  • 热斑漏检率↓78%!陌讯多模态算法在无人机光伏巡检的轻量化实践
  • 问题大全【1】
  • 【深度解析】R语言与作物模型(以DSSAT模型为例)融合应用
  • 散点图(散点矩阵)相关介绍
  • 【计算机科学与应用】基于多域变换的视频水印嵌入算法研究
  • 电脑出现英文字母开不了机怎么办 原因与修复方法
  • 开发笔记 | 实现人物立绘的差分效果
  • 达梦有多少个模式
  • 低成本嵌入式Linux开发方案:通过配置文件实现参数设置
  • LeetCode 68:文本左右对齐
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘papermill’问题
  • Docker搭建Hadoop集群
  • 进程管理(systemd)
  • 企业微信服务商创建第三方应用配置数据回调url和指令回调url的java代码实现
  • Python系统交互库全解析
  • Entity Framework Core (EF Core) 中Database
  • 归雁思维:解锁自然规律与人类智慧的桥梁
  • Online Proofing System(OPS)在线校样系统使用说明
  • Linux进程概念(五)进程地址空间
  • Leaflet 综合案例 - 路径规划
  • 医疗领域非结构化数据处理技术突破与未来演进
  • svn与git Merge重要区别讲解
  • C# 提取字符串 指定开始和结尾字符
  • 人机交互打字游戏
  • C#高级:通过修改注册表实现系统代理服务器的启用、编辑和禁用
  • 【计算机网络】计算机网络中光猫、交换机、路由器、网关、MAC地址是什么?两台电脑是如何联通的?
  • 承装修试二级承包范围