LeetCode 热题 100 之 35. 搜索插入位置 74. 搜索二维矩阵 34. 在排序数组中查找元素的第一个和最后一个位置

本次三道题目

  1. 搜索插入位置

  2. 搜索二维矩阵

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

35. 搜索插入位置

复制代码
class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 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;
            }
        }
        // 循环结束时 left 就是插入位置
        return left;
    }
}
解题思路: 二分查找

初始化 left = 0right = nums.length - 1(闭区间)。

循环条件:left <= right

  • 计算 mid = left + (right - left) / 2(避免溢出)。

  • nums[mid] == target:直接返回 mid

  • nums[mid] < target:目标在右侧,left = mid + 1

  • nums[mid] > target:目标在左侧,right = mid - 1

循环结束时,left 就是目标值应插入的位置(此时 left > rightleft 指向第一个大于 target 的位置)。

为什么会溢出?

在 Java 中,int 类型的取值范围是 [-2^31, 2^31 - 1](即 -2147483648 ~ 2147483647)。

  • 直接计算 (left + right) / 2:如果 leftright 都是接近 2^31 - 1 的大数(比如 left = 2147483640right = 2147483647),left + right 会超出 int 的最大值,触发整数溢出 ,结果变成负数(比如 2147483640 + 2147483647 = 4294967287,超出 2^31 - 1,实际存储为 -2147483641),导致 mid 计算错误。

  • 计算 left + (right - left) / 2right - left 是两个大数的差值,结果远小于 2^31 - 1,不会溢出;再加上 left,最终结果和 (left + right) / 2 等价,但完全避免了溢出风险。

74. 搜索二维矩阵

复制代码
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        int m = matrix.length;
        int n = matrix[0].length;
        int left = 0;
        int right = m * n - 1;
        
        while (left <= right) {
            int mid = left + (right - left) / 2; // 避免溢出
            int row = mid / n;
            int col = mid % n;
            if (matrix[row][col] == target) {
                return true;
            } else if (matrix[row][col] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return false;
    }
}

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length, n = matrix[0].length;
        int low = 0, high = m * n - 1;
        while (low <= high) {
            int mid = (high - low) / 2 + low;
            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;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/search-a-2d-matrix/solutions/688117/sou-suo-er-wei-ju-zhen-by-leetcode-solut-vxui/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解题思路1:一次二分查找

把二维矩阵 matrix[m][n] 映射成一维数组:

  • 一维索引 idx 对应二维坐标:

    • 行号 row = idx // n

    • 列号 col = idx % n

  • 初始左指针 left = 0,右指针 right = m * n - 1

  • 每次取中间值 mid = (left + right) // 2,转换为二维坐标后和 target 比较:

    • matrix[row][col] == target → 找到,返回 true

    • matrix[row][col] < target → 目标在右侧,left = mid + 1

    • matrix[row][col] > target → 目标在左侧,right = mid - 1

  • 循环结束仍未找到 → 返回 false

    class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
    int rowIndex = binarySearchFirstColumn(matrix, target);
    if (rowIndex < 0) {
    return false;
    }
    return binarySearchRow(matrix[rowIndex], target);
    }

    复制代码
      public int binarySearchFirstColumn(int[][] matrix, int target) {
          int low = -1, high = matrix.length - 1;
          while (low < high) {
              int mid = (high - low + 1) / 2 + low;
              if (matrix[mid][0] <= target) {
                  low = mid;
              } else {
                  high = mid - 1;
              }
          }
          return low;
      }
    
      public boolean binarySearchRow(int[] row, int target) {
          int low = 0, high = row.length - 1;
          while (low <= high) {
              int mid = (high - low) / 2 + low;
              if (row[mid] == target) {
                  return true;
              } else if (row[mid] > target) {
                  high = mid - 1;
              } else {
                  low = mid + 1;
              }
          }
          return false;
      }

    }

    作者:力扣官方题解
    链接:https://leetcode.cn/problems/search-a-2d-matrix/solutions/688117/sou-suo-er-wei-ju-zhen-by-leetcode-solut-vxui/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解题思路2:两次二分查找

由于每行的第一个元素大于前一行的最后一个元素,且每行元素是升序的,所以每行的第一个元素大于前一行的第一个元素,因此矩阵第一列的元素是升序的。

我们可以对矩阵的第一列的元素二分查找,找到最后一个不大于目标值的元素,然后在该元素所在行中二分查找目标值是否存在。

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

非递减 有序数组 (也叫 "非严格递增数组")是指:数组中每个元素都大于或等于 它前面的元素(nums[i] ≥ nums[i-1]i > 0)。

复制代码
class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = findLeft(nums, target);
        int right = findRight(nums, target);
        // 不存在的情况
        if (left == nums.length || nums[left] != target) {
            return new int[]{-1, -1};
        }
        return new int[]{left, right};
    }

    // 找左边界:第一个 >= target 的位置
    private int findLeft(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] >= target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

    // 找右边界:最后一个 <= target 的位置(比基于找到左边界再遍历快一点数据大的话)
    private int findRight(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] <= target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return right;
    }
}
解题思路:两次二分查找

找左边界

  • 初始化 left = 0, right = len(nums) - 1

  • 循环条件:left <= right

  • nums[mid] >= target 时,说明左边界在左半部分,令 right = mid - 1

  • nums[mid] < target 时,说明左边界在右半部分,令 left = mid + 1

  • 循环结束后,left 即为第一个 ≥ target 的位置,若 left 越界或 nums[left] != target,则不存在

找右边界

  • 初始化 left = 0, right = len(nums) - 1

  • 循环条件:left <= right

  • nums[mid] <= target 时,说明右边界在右半部分,令 left = mid + 1

  • nums[mid] > target 时,说明右边界在左半部分,令 right = mid - 1

  • 循环结束后,right 即为最后一个 ≤ target 的位置,若 right 越界或 nums[right] != target,则不存在

相关推荐
xiaoye-duck2 分钟前
《算法题讲解指南:优选算法-队列+宽搜》--70.N叉树的层序遍历,71.二叉树的锯齿形层序遍历,72.二叉树的最大宽度,73.在每个树行中找最大值
数据结构·c++·算法·队列
汀、人工智能4 分钟前
[特殊字符] 第98课:数据流中位数
数据结构·算法·数据库架构··数据流·数据流中位数
Eloudy7 分钟前
不同特征值的特征向量互相正交的矩阵
人工智能·算法·机器学习
人道领域9 分钟前
【LeetCode刷题日记】:从 LeetCode 经典题看哈希表的场景化应用---数组、HashSet、HashMap 选型与算法实战
算法·leetcode·面试
努力努力再努力wz10 分钟前
【C++高阶系列】告别内查找局限:基于磁盘 I/O 视角的 B 树深度剖析与 C++ 泛型实现!(附B树实现源码)
java·linux·开发语言·数据结构·c++·b树·算法
承渊政道11 分钟前
【优选算法】(实战攻坚BFS之FloodFill、最短路径问题、多源BFS以及解决拓扑排序)
数据结构·c++·笔记·学习·算法·leetcode·宽度优先
kishu_iOS&AI12 分钟前
机器学习 —— 线性回归(2)
人工智能·python·算法·机器学习·线性回归
NULL指向我15 分钟前
信号处理学习笔记6:ADC采样线性处理实测拟合
人工智能·算法·机器学习
汽车仪器仪表相关领域18 分钟前
NHXJ-02汽车悬架检验台 实操型实战手册
人工智能·功能测试·测试工具·算法·安全·单元测试·可用性测试
源码之屋19 分钟前
计算机毕业设计:Python天气数据采集与可视化分析平台 Django框架 线性回归 数据分析 大数据 机器学习 大模型 气象数据(建议收藏)✅
人工智能·python·深度学习·算法·django·线性回归·课程设计