Leetcode 刷题记录 15 —— 二分查找

发布于:2025-06-16 ⋅ 阅读:(18) ⋅ 点赞:(0)

本系列为笔者的 Leetcode 刷题记录,顺序为 Hot 100 题官方顺序,根据标签命名,记录笔者总结的做题思路,附部分代码解释和疑问解答,01~07为C++语言,08及以后为Java语言。

01 搜索插入位置

在这里插入图片描述

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

02 搜索二维矩阵

在这里插入图片描述

在这里插入图片描述

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        //思路:将二维数组展开为一维数组
        int row = matrix.length;
        int column = matrix[0].length;
        int left = 0;
        int right = row * column - 1;

        while(left <= right){
            int mid = (left + right) / 2;
            int x = matrix[mid / column][mid % column];
            if(x == target){
                return true;
            }else if(x < target){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }
        return false;
    }
}

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

在这里插入图片描述

在这里插入图片描述

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] positions = new int[]{-1, -1};
        int left1 = 0, left2 = 0;
        int right1 = nums.length-1, right2 = nums.length-1;

        //寻找第一个等于target的位置
        while(left1 <= right1){
            int mid1 = (left1 + right1) / 2;
            if(nums[mid1] == target){
                positions[0] = mid1;
                right1 = mid1 - 1; //重点
            }else if(nums[mid1] < target){
                left1 = mid1 + 1;
            }else{
                right1 = mid1 - 1;
            }
        }

        //寻找最后一个等于target的位置
        while(left2 <= right2){
            int mid2 = (left2 + right2) / 2;
            if(nums[mid2] == target){
                positions[1] = mid2;
                left2 = mid2 + 1; //重点
            }else if(nums[mid2] < target){
                left2 = mid2 + 1;
            }else{
                right2 = mid2 - 1;
            }
        }

        return positions;
    }
}

第一个重点确保了即使找到目标值,也会继续向左搜索,以确保找到第一个出现的索引。

第二个重点确保了即使找到目标值,也会继续向右搜索,以确保找到最后一个出现的索引。

04 搜索旋转排序数组 ⭐

在这里插入图片描述

在这里插入图片描述

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 left = 0;
        int right = n - 1;
        while(left <= right){
            int mid = (left + right) / 2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[0] <= nums[mid]){ //大山峰、小山峰
                if(nums[0] <= target && target < nums[mid]){
                    right = mid - 1;
                }else{
                    left = mid + 1;
                }
            }else{ //小山峰、大山峰
                if(nums[mid] < target && target <= nums[n - 1]){
                    left = mid + 1;
                }else{
                    right = mid - 1;
                }
            }
        }

        return -1;
    }
}

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

在这里插入图片描述

在这里插入图片描述

class Solution {
    public int findMin(int[] nums) {
        int n = nums.length;

        //特殊情况判断
        if(n == 1){
            return nums[0];
        }

        int left = 0;
        int right = n - 1;
        int flag = nums[0];
        while(left <= right){
            int mid = (left + right) / 2;
            flag = nums[mid] < flag ? nums[mid] : flag;
            if(nums[0] <= nums[mid]){ //大山峰、小山峰
                left = mid + 1;
            }else{ //小山峰、大山峰
                right = mid - 1;
            }
        }
        return flag;
    }
}

06 寻找两个正序数组的中位数

在这里插入图片描述

如果对时间复杂度的要求有log,通常都需要用到二分查找。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length, n = nums2.length;
        int numsLength = m + n;

        if(numsLength % 2 == 1){
            int mid = numsLength / 2 + 1;
            double ans = myFunction(nums1, nums2, mid); //寻找第k小的数
            return ans;
        }else{
            int mid1 = numsLength / 2;
            int mid2 = numsLength / 2 + 1;
            double ans = (myFunction(nums1, nums2, mid1) + myFunction(nums1, nums2, mid2)) / 2.0;
            return ans;
        }
    }

    public int myFunction(int[] nums1, int[] nums2, int k){
        int m = nums1.length, n = nums2.length;
        int index1 = 0, index2 = 0;
        
        while(true){
            //特殊情况判断
            if(index1 == m){
                return nums2[index2 + k - 1];
            }
            if(index2 == n){
                return nums1[index1 + k - 1];
            }
            if(k == 1){
                return Math.min(nums1[index1], nums2[index2]);
            }
            
            int half = k / 2;
            int newIndex1 = Math.min(index1 + half, m) - 1;
            int newIndex2 = Math.min(index2 + half, n) - 1;
            int pivot1 = nums1[newIndex1];
            int pivot2 = nums2[newIndex2];

            //重点
            if(pivot1 <= pivot2){
                k -= (newIndex1 - index1 + 1);
                index1 = newIndex1 + 1;
            }else{
                k -= (newIndex2 - index2 + 1);
                index2 = newIndex2 + 1;
            }
        }
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到