【二分查找】【中等】搜索二维矩阵/排序数组的第一位和最后位置/搜索旋转排序数组/旋转排序数组中的最小值

1.搜索二维矩阵

原题链接

  • 注意要求代码的时间复杂度为 O(log(m * n))
  • 对于整体的数组进行二分查找,在定位到数组中的位置
java 复制代码
public boolean searchMatrix(int[][] matrix, int target) {
    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;
        if (matrix[mid / n][mid % n] == target) {
            return true;
        }
        if (matrix[mid / n][mid % n] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return false;
}

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

原题链接

  • 题目要求时间复杂度是 O(log n)
  • 进行两次二分查找:寻找两个边界
    • 第一次二分:找最左边的 target
    • 第二次二分:找最右边的 target
java 复制代码
public int[] searchRange(int[] nums, int target) {
    int start = findStart(nums, target);
    int end = findEnd(nums, target);
    return new int[]{start, end};
}
//寻找左端点
private int findStart(int[] nums, int target) {
    int ans = -1;
    int left = 0;
    int right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            ans = mid;
            right = mid - 1;
        }
        if (nums[mid] < target) {
            left = mid + 1;
        }
        if (nums[mid] > target) {
            right = mid - 1;
        }
    }
    return ans;
}
//寻找右端点
private int findEnd(int[] nums, int target){
    int ans = -1;
    int left = 0;
    int right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            ans = mid;
            left = mid + 1;
        }
        if (nums[mid] < target) {
            left = mid + 1;
        }
        if (nums[mid] > target) {
            right = mid - 1;
        }
    }
    return ans;
}

简化后的代码

java 复制代码
public int[] searchRange(int[] nums, int target) {
    int first = lowerBound(nums, target);
    // 没找到 target
    if (first == nums.length || nums[first] != target) {
        return new int[]{-1, -1};
    }
    int last = lowerBound(nums, target + 1) - 1;
    return new int[]{first, last};
}
// 找第一个 >= target 的位置
private int lowerBound(int[] nums, int target) {
    int left = 0;
    int right = nums.length;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] >= target) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    return left;
}

3.搜索旋转排序数组⭐

原题链接

  • 每次通过 mid 进行二分查找的时候,得到的结果要么 左半部分有序右半部分无序 或者 左半部分无序右半部分有序
  • nums 中的每个值都 独一无二,因此不存在重叠范围的问题
  • 可以通过 left、mid、right 的值判断左右有序的数组,如果 target 在有序数组中则直接二分查找,否则在递归进行判断
bash 复制代码
下标: 0 1 2 3 4 5 6
数组:[4,5,6,7,0,1,2]
            ↑
           mid
java 复制代码
public int search(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;
        }
        //判断是否左有序
        if (nums[left] <= nums[mid]) {
            //判断target是否在左有序区间
            if (target >= nums[left] && target <= nums[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        } else {
            //判断target是否在右有序区间
            if (target >= nums[mid] && target <= nums[right]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
    }
    return -1;
}

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

原题链接

  • 最小值其实就是两个有序部分的分界点
  • 同样二分查找中,min将数组分为左右两侧,左有序右无序或左五序右有序
  • 无序的一侧则继续递归
java 复制代码
public int findMin(int[] nums) {
    int left = 0;
    int right = nums.length - 1;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] > nums[right]) {
            // 最小值一定在 mid 右边
            left = mid + 1;
        } else {
            // 最小值可能是 mid,也可能在 mid 左边
            right = mid;
        }
    }
    return nums[left];
}
相关推荐
土司大王1 小时前
LeetCode hot100——153.寻找旋转排序数组中的最小值:Java 二分模板与 O(log n) 分析
java·算法·leetcode
光电的一只菜鸡1 小时前
isp中关于锐化对图像清晰度的影响
算法
磐链科技1 小时前
交易所开发中的合规与安全:KYC、AML、冷热钱包设计要点
java·区块链
码农飞哥2 小时前
企业级RAG系统架构详解
java·人工智能·ai编程·rag·ai应用
Wang's Blog2 小时前
Java框架快速入门: Spring Security+OAuth2之搭建授权服务器(依赖与表结构)
java·服务器·spring
土司大王2 小时前
LeetCode hot100——4.寻找两个正序数组的中位数:Java 二分第K小 递归裁剪
java·算法·leetcode
dllxhcjla2 小时前
SpringAI+DeepSeek大模型应用开发
java
薛定e的猫咪2 小时前
(ICML2024)QSM:基于 Q 函数梯度对齐分数场的扩散模型离策略强化学习
人工智能·深度学习·算法
小鱼干..2 小时前
青少年ctf url
java