刷题小记10:二分查找

二分查找的思路不难理解,但是边界条件容易出错,比如 循环结束条件中 left 和 right 的关系,更新 left 和 right 位置时要不要加 1 减 1。到底是 while(left < right) 还是 while(left <= right),到底是right = middle呢,还是要right = middle - 1呢?

第一种写法,我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right] (这个很重要非常重要)

区间的定义这就决定了二分法的代码应该如何写,因为定义target在[left, right]区间,所以有如下两点:

  • while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=
  • if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

二分模板 

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1; // 注意
        while(left <= right) { // 注意
            int mid = (left + right) / 2; // 注意
            if(nums[mid] == target) { // 注意
                // 相关逻辑
            } else if(nums[mid] < target) {
                left = mid + 1; // 注意
            } else {
                right = mid - 1; // 注意
            }
        }
        // 相关返回值
        return 0;
    }
}

35.搜索插入位置

搜索插入位置

每次根据 nums[mid] 和 target 之间的大小进行判断,相等则直接返回下标,nums[mid] < target 则 left 右移,nums[mid] > target 则 right 左移
查找结束如果没有相等值则返回 left,该值为插入位置
时间复杂度:O(logn)

为什么直接return left?

因为如果上面的没有返回return middle,说明最后一定是,left>right从而跳出循环的,在此之前是left=right,如果最后是right-1导致的left>right,说明原来的right位置是大于target的,所以返回原来的right位置即left位置;

如果最后是left+1导致的left>right,说明是原来的的left=right这个位置小于target,而right能移动到这个位置,说明此位置右侧是大于target的,left现在加1就移动到了这样的位置,返回left即可

作者:画手大鹏
链接:https://leetcode.cn/problems/search-insert-position/solutions/8017/hua-jie-suan-fa-35-sou-suo-cha-ru-wei-zhi-by-guanp/
来源:力扣(LeetCode

74.搜索二维矩阵

搜索二维矩阵

方法一:两次二分,先搜索列再搜索行

方法二:与240题一样的抽象BST做法

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

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

思路

二分查找左右边界

  • 不可以找到 target 以后,然后向两边扩散(线性查找),这样的话时间复杂度为 O(N)
  • 找 target 第一次出现的位置和最后一次出现的位置的时候,都只能用「二分查找」才符合题目的意思,注意分类讨论,并且把分类讨论的结果合并。

33.搜索排序数组

搜索旋转排序数组

思路

先判断哪半段是有序的,然后判断目标是否在有序的那半里面

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

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

在这个数组中,至少有一个地方,数组的顺序被打破,这个打破的地方就是无序区间。

证明

  1. 定义有序与无序:

    • 假设数组 nums 的长度为 n,且经过旋转后形成两部分:有序部分无序部分
    • 有序部分是指在某个区间内所有元素是升序排列的;无序部分是指该区间内的元素顺序被打破。
  2. 无序区间的性质:

    • 如果我们在数组中找到一个无序区间,那么这个区间的左端点一定是该区间的最大值,而右端点是最小值。例如,在 [4, 5, 1, 2, 3] 中,4 和 5 是有序的,而 1 是无序区间的起始点,最小值在无序区间。
  3. 推理步骤:

    • 当你选择某个元素 mid 并比较 nums[left] 和 nums[mid] 时,你可以得出以下结论:
      • Case 1: 如果 nums[left] <= nums[mid],则说明从 left 到 mid 这个区间是有序的。
        • 在这种情况下,最小值一定不在这个有序区间内,而是在右边的无序部分中。
      • Case 2: 如果 nums[left] > nums[mid],则说明从 left 到 mid 这个区间是无序的。
        • 在这种情况下,最小值必然位于这个无序部分中,因为它是被旋转打乱的区间,包含了原始数组的最小元素。
  4. 结束条件:

    • 当 left 和 right 重合时(即 left == right),此时 nums[left](或 nums[right])就是数组中的最小值。

直观理解

  • 设想你在一个有序的数组中找最小值,任何时候你都能找到最小值,因为它不会出现在有序区间的末尾。
  • 当数组被旋转,分成有序部分和无序部分时,最小值必定是在这个无序部分,因为有序部分的最小值比无序部分的任何值都要大。

4. 寻找两个正序数组的中位数

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

题解:力扣(LeetCode)配合 官方题解的视频使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值