【思路详解+详细注释】小白都能看懂的力扣算法详解——二分查找

一 LC35.搜索插入位置

题目要求:

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

35. 搜索插入位置 - 力扣(LeetCode)

思路分析:

       这是一个经典的二分查找位置,在之前力扣算法带刷——二分查找法_力扣mid-CSDN博客这篇博客中也有详细讲解过,我们需要在一个排序数组中找到目标值的位置,或者找出目标值应该插入的位置。由于数组是排序的,所以可以通过二分查找将时间复杂度优化为 O(log n)。

        我们定义左、右两个指针分别指向数组头、尾元素,当左指针小于等于右指针时循环计算中间值mid,并比较mid指向的元素与目标值大小,如果相等直接返回mid即可,不等则判断谁更大,如果mid指向的元素更大,则缩短区间为[左指针,中间指针-1],否则缩短区间为[中间指针+1,右指针],直到找到与目标值相等的元素索引或者左指针大于右指针时,此时说明没有找到目标值,我们直接返回左指针,也就是该值应该插入的位置(此时它左侧的元素都小于它,它右侧的数据都大于它)。

完整代码示例:

public 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;
            }
        }
        
        return left;
    }
}

二 LC74.搜索二维矩阵

题目要求:

给你一个满足下述两条属性的 m x n 整数矩阵:

  • 每行中的整数从左到右按非严格递增顺序排列。
  • 每行的第一个整数大于前一行的最后一个整数。

给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。

74. 搜索二维矩阵 - 力扣(LeetCode)

思路分析:

       由于每行的第一个元素大于前一行的最后一个元素,且每行元素非严格递增,因此整个矩阵可以认为是一个从左上到右下的升序数组。我们可以对这个虚拟的一维数组应用二分查找。

        我们可以将矩阵看作是一个由 m * n 个元素组成的一维数组,其中第 mid 个元素对应的二维索引为:row = mid / n, col = mid % n,其中 n 是矩阵的列数。之后我们通过二分查找的方式查找 target,初始化 left = 0right = m * n - 1,计算 mid,并通过上面的公式找到 mid 对应的矩阵元素 matrix[row][col]

        之后就是常规的二分查找操作了。如果 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) {
         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 midVal = matrix[mid / n][mid % n];  // 映射到二维矩阵的行和列

            if (midVal == target) {
                return true;
            } else if (midVal < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return false;
    }
}

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

题目要求:

吖吖

思路分析:

       使用两次二分查找,分别查找左边界和右边界,每个边界的查找方法都是基础的二分查找,区别在于在找到对应索引后,要继续向两侧查找是否有其他目标值存在,如果存在则覆盖

完整代码示例:

class Solution {
    public int[] searchRange(int[] nums, int target) {
         int leftRange = -1;  // 左边界
        int rightRange = -1;  // 右边界
        leftRange = searchLeft(nums, target, leftRange);  // 查找左边界
        rightRange = searchRight(nums, target, rightRange);  // 查找右边界
        return new int[]{leftRange, rightRange};  // 返回左右边界数组
    }
    // 查找右边界
    private int searchRight(int[] nums, int target, int rightRange) {
        int left = 0;  // 左边界(左闭右闭)
        int right = nums.length - 1;  // 右边界
        int mid = 0;  // 中间位置
 
        while (left <= right) {
            mid =(left+right)/2;  // 计算中间位置,避免溢出
            if (nums[mid] == target) {
                rightRange = mid;  // 更新右边界为当前位置
                left = mid + 1;  // 继续向右搜索
            } else if (nums[mid] > target) {
                right = mid - 1;  // 目标值在左半部分,更新右边界
            } else {
                left = mid + 1;  // 目标值在右半部分,更新左边界
            }
        }
        return rightRange;  // 返回右边界
    }
 // 查找左边界
    private int searchLeft(int[] nums, int target, int leftRange) {
        int left = 0;  // 左边界
        int right = nums.length - 1;  // 右边界
        int mid = 0;  // 中间位置
 
        while (left <= right) {
            mid = (left+right)/2;  // 计算中间位置,避免溢出
            if (nums[mid] == target) {
                leftRange = mid;  // 更新左边界为当前位置
                right = mid - 1;  // 继续向左搜索
            } else if (nums[mid] > target) {
                right = mid - 1;  // 目标值在左半部分,更新右边界
            } else {
                left = mid + 1;  // 目标值在右半部分,更新左边界
            }
        }
        return leftRange;  // 返回左边界

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值