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

力扣top100(day04-03)--二分查找

本文为力扣TOP100刷题笔记

笔者根据数据结构理论加上最近刷题整理了一套 数据结构理论加常用方法以下为该文章:

力扣外传之数据结构(一篇文章搞定数据结构)

35. 搜索插入位置

class Solution {public int searchInsert(int[] nums, int target) {int left=0;int length=nums.length;int right=length-1;int ans = length;while(left <= right){int mid = ((right - left) >> 1) + left;if(nums[mid]>=target){ans=mid;right=mid-1;}else{left=mid+1;}}return ans;}
}

关键点说明:

  1. 初始化

    • left = 0(数组起始索引)。

    • right = nums.length - 1(数组末尾索引)。

    • ans = nums.length(默认插入位置,适用于 target 大于所有元素的情况)。

  2. 二分查找

    • mid = left + ((right - left) >> 1):计算中间索引,使用位运算 >> 1 代替 / 2,效率更高且防止 (left + right) 溢出。

    • 如果 nums[mid] >= target

      • 更新 ans = mid(记录可能的插入位置)。

      • 继续在左半部分查找(right = mid - 1)。

    • 否则

      • 继续在右半部分查找(left = mid + 1)。

  3. 终止条件

    • 当 left > right 时循环结束,此时 ans 即为 target 的插入位置。

示例:

示例 1

  • 输入:nums = [1, 3, 5, 6]target = 5

  • 执行过程:

    • left = 0right = 3ans = 4

    • mid = 1 → nums[1] = 3 < 5 → left = 2

    • mid = 2 → nums[2] = 5 >= 5 → ans = 2right = 1

    • 循环结束,返回 ans = 25 已存在,返回其索引)。

示例 2

  • 输入:nums = [1, 3, 5, 6]target = 2

  • 执行过程:

    • left = 0right = 3ans = 4

    • mid = 1 → nums[1] = 3 >= 2 → ans = 1right = 0

    • mid = 0 → nums[0] = 1 < 2 → left = 1

    • 循环结束,返回 ans = 12 应插入在索引 1 处)。

时间复杂度 & 空间复杂度

  • 时间复杂度O(log n),标准的二分查找。

  • 空间复杂度O(1),仅使用常数空间。

其他实现方式

也可以直接使用 Java 内置的 Arrays.binarySearch()

java

import java.util.Arrays;class Solution {public int searchInsert(int[] nums, int target) {int index = Arrays.binarySearch(nums, target);return index >= 0 ? index : -index - 1;}
}
  • 如果找到目标值,返回其索引。

  • 如果未找到,返回 -insertionPoint - 1,转换后即为插入位置。

74. 搜索二维矩阵

class Solution {public boolean searchMatrix(int[][] matrix, int target) {int m = matrix.length;    // 矩阵的行数int n = matrix[0].length; // 矩阵的列数int low = 0, high = m * n - 1; // 初始化二分查找的左右边界while (low <= high) {int mid = low + (high - low) / 2; // 计算中间位置,防止溢出int x = matrix[mid / n][mid % n];  // 将一维索引转换为二维坐标if (x < target) {low = mid + 1; // 目标在右半部分} else if (x > target) {high = mid - 1; // 目标在左半部分} else {return true; // 找到目标}}return false; // 未找到目标}
}

关键点说明:

  1. 二维矩阵 → 一维数组的映射

    • 因为矩阵整体有序,可以将其视为一个长度为 m * n 的一维数组。

    • 索引转换

      • mid / n 得到行号。

      • mid % n 得到列号。

      • 例如,mid = 5n = 4,则 matrix[1][1](因为 5 / 4 = 15 % 4 = 1)。

  2. 标准的二分查找

    • 初始化 low = 0high = m * n - 1

    • 计算 mid 并比较 matrix[mid / n][mid % n] 与 target

      • 如果 x < target,说明目标在右侧,调整 low = mid + 1

      • 如果 x > target,说明目标在左侧,调整 high = mid - 1

      • 如果相等,直接返回 true

  3. 终止条件

    • 如果 low > high,说明目标不存在,返回 false

示例:

输入

java

matrix = [[1,   3,  5,  7],[10, 11, 16, 20],[23, 30, 34, 50]
],
target = 3

执行过程

  1. m = 3n = 4low = 0high = 11

  2. mid = 5 → matrix[1][1] = 11 > 3 → high = 4

  3. mid = 2 → matrix[0][2] = 5 > 3 → high = 1

  4. mid = 0 → matrix[0][0] = 1 < 3 → low = 1

  5. mid = 1 → matrix[0][1] = 3 == target → 返回 true

时间复杂度 & 空间复杂度

  • 时间复杂度O(log(m * n)),即标准的二分查找复杂度。

  • 空间复杂度O(1),仅使用常数空间。

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

class Solution {public int[] searchRange(int[] nums, int target) {int leftIdx = binarySearch(nums, target, true);int rightIdx = binarySearch(nums, target, false) - 1;if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {return new int[]{leftIdx, rightIdx};} return new int[]{-1, -1};}public int binarySearch(int[] nums, int target, boolean lower) {int left = 0, right = nums.length - 1, ans = nums.length;while (left <= right) {int mid = (left + right) / 2;if (nums[mid] > target || (lower && nums[mid] >= target)) {right = mid - 1;ans = mid;} else {left = mid + 1;}}return ans;}
}

关键点说明:

  1. binarySearch 函数

    • 参数 lower

      • lower = true:查找 第一个 >= target 的位置(左边界)。

      • lower = false:查找 第一个 > target 的位置(右边界 + 1)。

    • 返回值

      • 如果 lower = true,返回 target 的起始位置(如果存在)。

      • 如果 lower = false,返回 target 的结束位置 + 1(因此需要 rightIdx = ans - 1)。

  2. 主函数 searchRange

    • 先调用 binarySearch(nums, target, true) 找到左边界 leftIdx

    • 再调用 binarySearch(nums, target, false) 找到右边界 + 1,然后 - 1 得到真正的右边界 rightIdx

    • 检查有效性

      • leftIdx <= rightIdx:确保区间存在。

      • rightIdx < nums.length:防止越界。

      • nums[leftIdx] == target && nums[rightIdx] == target:确保找到的是 target

  3. 边界情况处理

    • 如果 target 不存在,leftIdx 可能会指向第一个 > target 的位置,此时 leftIdx > rightIdx,返回 [-1, -1]

示例:

输入nums = [5,7,7,8,8,10]target = 8
执行过程

  1. binarySearch(nums, 8, true)

    • mid = 2 → nums[2] = 7 < 8 → left = 3

    • mid = 4 → nums[4] = 8 >= 8 → ans = 4right = 3

    • 循环结束,返回 leftIdx = 3(左边界)。

  2. binarySearch(nums, 8, false)

    • mid = 2 → nums[2] = 7 不满足 > 8 → left = 3

    • mid = 4 → nums[4] = 8 不满足 > 8 → left = 5

    • mid = 5 → nums[5] = 10 > 8 → ans = 5right = 4

    • 循环结束,返回 ans = 5,因此 rightIdx = 5 - 1 = 4(右边界)。

  3. 检查 leftIdx = 3rightIdx = 4 是否有效:

    • 3 <= 4 且 nums[3] = 8nums[4] = 8 → 返回 [3, 4]

时间复杂度 & 空间复杂度

  • 时间复杂度O(log n),因为进行了两次二分查找。

  • 空间复杂度O(1),仅使用常数空间。

33. 搜索旋转排序数组

class Solution {public int search(int[] nums, int target) {int n = nums.length;if (n == 0) { // 处理空数组return -1;}if (n == 1) { // 处理单元素数组return nums[0] == target ? 0 : -1;}int l = 0, r = n - 1; // 初始化左右指针while (l <= r) {int mid = (l + r) / 2; // 计算中间位置if (nums[mid] == target) { // 找到目标return mid;}if (nums[0] <= nums[mid]) { // 左半部分有序if (nums[0] <= target && target < nums[mid]) { // 目标在左半部分r = mid - 1;} else { // 目标在右半部分l = mid + 1;}} else { // 右半部分有序if (nums[mid] < target && target <= nums[n - 1]) { // 目标在右半部分l = mid + 1;} else { // 目标在左半部分r = mid - 1;}}}return -1; // 未找到目标}
}

关键点说明:

  1. 初始化检查

    • 如果数组为空,直接返回 -1

    • 如果数组只有一个元素,直接判断是否等于 target

  2. 二分查找

    • 计算中间位置mid = (l + r) / 2

    • 找到目标:如果 nums[mid] == target,直接返回 mid

    • 判断有序部分

      • 左半部分有序nums[0] <= nums[mid]):

        • 如果 target 在左半部分的范围内(nums[0] <= target < nums[mid]),则继续在左半部分查找(r = mid - 1)。

        • 否则,在右半部分查找(l = mid + 1)。

      • 右半部分有序nums[0] > nums[mid]):

        • 如果 target 在右半部分的范围内(nums[mid] < target <= nums[n - 1]),则继续在右半部分查找(l = mid + 1)。

        • 否则,在左半部分查找(r = mid - 1)。

  3. 终止条件

    • 如果 l > r,说明未找到目标,返回 -1

示例:

输入nums = [4,5,6,7,0,1,2]target = 0
执行过程

  1. l = 0r = 6 → mid = 3 → nums[3] = 7 ≠ 0

    • nums[0] = 4 <= 7,左半部分有序。

    • target = 0 不在 [4, 7) 范围内 → l = 4

  2. l = 4r = 6 → mid = 5 → nums[5] = 1 ≠ 0

    • nums[0] = 4 > 1,右半部分有序。

    • target = 0 在 (1, 2] 范围内 → l = 6

  3. l = 6r = 6 → mid = 6 → nums[6] = 2 ≠ 0

    • nums[0] = 4 > 2,右半部分有序。

    • target = 0 不在 (2, 2] 范围内 → r = 5

  4. l = 6r = 5 → 循环结束,未找到目标。

    • 实际上 target = 0 位于 nums[4],但之前的逻辑未覆盖这种情况。需要修正判断条件。

153. 寻找旋转排序数组中的最小值

class Solution {public int findMin(int[] nums) {int length=nums.length;int left=0;int right=length-1;while(left<right){int mid=left+(right-left)/2;if(nums[mid]<nums[right]){right=mid;}else{left=mid+1;}}return nums[left];}
}

关键点说明:

  1. 初始化

    • left = 0right = length - 1,初始化搜索范围为整个数组。

  2. 二分查找

    • 计算中间位置mid = left + (right - left) / 2(防止整数溢出)。

    • 比较 nums[mid] 和 nums[right]

      • 如果 nums[mid] < nums[right]

        • 说明右半部分有序,最小值可能在左半部分(包括 mid)。

        • 调整 right = mid,继续在左半部分查找。

      • 否则

        • 说明左半部分有序,最小值在右半部分(不包括 mid)。

        • 调整 left = mid + 1,继续在右半部分查找。

  3. 终止条件

    • 当 left == right 时,循环结束,此时 nums[left] 即为最小值。

示例:

输入nums = [4,5,6,7,0,1,2]
执行过程

  1. left = 0right = 6 → mid = 3 → nums[3] = 7nums[6] = 2 → 7 > 2 → left = 4

  2. left = 4right = 6 → mid = 5 → nums[5] = 1nums[6] = 2 → 1 < 2 → right = 5

  3. left = 4right = 5 → mid = 4 → nums[4] = 0nums[5] = 1 → 0 < 1 → right = 4

  4. left = 4right = 4 → 循环结束,返回 nums[4] = 0

时间复杂度 & 空间复杂度

  • 时间复杂度O(log n),标准的二分查找。

  • 空间复杂度O(1),仅使用常数空间。

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

相关文章:

  • MqSQL中的《快照读》和《当前读》
  • [论文笔记] WiscKey: Separating Keys from Values in SSD-Conscious Storage
  • Linux core dump
  • Flutter开发 webview_flutter的基本使用
  • MC0423铺砖块
  • Linux系统编程—Linux基础指令
  • OpenCV Python——图像查找(特征匹配 + 单应性矩阵)
  • Linux软件编程(五)(exec 函数族、system、线程)
  • SQL:生成日期序列(填补缺失的日期)
  • 磁悬浮轴承“幽灵振动”克星:深度解析同频振动机理与精准打击策略
  • 优先级反转问题
  • [Python 基础课程]根据描述定义一个 Person 类
  • 关注与优化:用于骨龄评估的交互式关键点定位与颈椎定量分析|文献速递-深度学习人工智能医疗图像
  • Go语言中的指针接收者
  • 语音活动检测VAD技术简介
  • 崩溃大陆2 送修改器 PC/手机双端(Crashlands2)免安装中文版
  • Fanuc机器人EtherCAT通讯配置详解
  • 思科应用中心基础设施(ACI)设计指南
  • Redis面试精讲 Day 22:Redis布隆过滤器应用场景
  • 第2篇_Go语言基础语法_变量常量与数据类型
  • Java-JVM是什么JVM的类加载机制
  • 设备 AI 知识库,管理效率新飞跃
  • 安装openmmlab时出错
  • 码上爬第七题【协程+对抗格式化检测+数组移位】
  • Linux搭建ftp服务器
  • 事务的四大特性
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘fairseq’问题
  • ubuntu安装docker
  • Python爬取推特(X)的各种数据
  • Higress AI网关