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

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];
}
相关推荐
用户3126874877205 分钟前
Java 对象内存布局:压缩指针、对齐填充与 JOL 实测
java
东华果汁哥21 分钟前
【Spring AI 实战】从零开始调用大模型接口,构建 Java AI 应用
java·人工智能·spring
深圳市益普科技有限公司36 分钟前
半导体良率管理YMS:良率与设备参数的相关性,先拉哪几组数据
人工智能·python·算法
挖井观天37 分钟前
《Java数据结构》第一讲:顺序表
数据结构
Song_RsHt1 小时前
Redis 与微服务,什么场景下无可替代
java·redis·后端·学习·微服务
学长毕设1 小时前
基于SpringBoot的建筑材料管理系统-附源码
java·spring boot·后端
摸爬滚打的小李2 小时前
关于 Arthas
java·后端
程序员清风2 小时前
算法题中的边界条件、测试与调试
开发语言·算法·kotlin
砚底藏山河2 小时前
python量化实操:冷热分层存储
java·开发语言·python·金融
yuniko-n2 小时前
【JUC】原子类
java