LeetcodeT74搜索二维矩阵

详细解释了二分查找在不同条件下该如何设定缩减边界,以及总结了几种模板。

二分查找的三种类型

写一个找准确值的都会写,但是每次稍作变换,比如“找比x大的最小的数”,或者如T34一样有重复值的左边界,等等,我就晕了orz。

看了一个b站视频,感觉自己仿佛懂了,因此在这里记录下来。

首先,无论如何,二分查找有两个必须要满足的条件:

  • 每次都要缩减搜索区域
  • 每次缩减不能排除掉答案

在以上条件的基础下,up主将不同类型的题目整理出如下的三大模板。

1.找准确值

这是最简单的情况,大家都会。

  • 循环条件 : start <= end

  • 缩减空间 : start = mid +1

    ​ end = mid -1

2.找模糊值

这就有好多情况了,题目里也经常遇到,比如找比target大的最小数这种,还有某个数的左边界右边界什么的,但依然注意这两件事就可以。

  • 循环条件 : start < end

  • 缩减空间 : start = mid

    ​ end = mid - 1

    ​ 或者: start = mid + 1

    ​ end = mid

那么这两种缩减空间应该在如何选择呢?举个例子,例如,想要寻找2的左边界,数组可能为两种情况:

1 1 2 ==2== 2 6 7
1 1 1 ==2== 2 6 7

查找到2后,这个2可能就是左边界,也可能它的左边还有2,因此要继续搜索左边的区域、并且不能排除掉这个2。

因此,此时的缩减空间应该为end = mid。也就对应的前文第二种缩减空间。

相应的,如果此时mid值小于2,那么mid值一定不会为答案,直接在右边查找就可以,缩减空间是start = mid + 1。

其他的时候也都依靠这种思路分析,发现比以前清楚了好多。

这里还有一个小问题,为什么这里的判断条件是start<end,而不是找准确值时的start<=end了呢?

这是因为,缩减时会有start = mid 或者 end = mid的情况,如果数组只有一个值,缩减也没用,会陷入死循环。

3.通用型

还有一种情况是,要找到最接近target的值。

  • 循环条件 : start < end - 1

  • 缩减空间 : start = mid

    ​ end = mid

    此时,start和end相邻时就可以结束了,因此缩减只要=mid就可以了。

    这种方法的优点就在于可以留下两个值,最后可以比较一下哪个更接近target。

mid的写法

mid的写法也有两点需要注意,第一是注意溢出的问题,第二是当数组长度为偶数时,指针会在中间偏左的数上,在某些条件下会死循环。有时应该让它在中间偏右的数上,也需要考虑一下。

可以参照的写法如下:

mid = start + (end - start)/2;
mid = start + (end - start+1)/2;

Leetcode T74

学好了思路就开始做题。首先我想要在第一列中,找出小于等于target的数里,最大的那一个。

那么缩减空间应该是什么样的呢?

如果mid大于target,答案肯定在左侧,不会包括mid,也就是end=mid-1 ;

如果mid小于target,答案可能是mid,也可能还在右边,因此start = mid 。

接下来考虑mid的问题,由于缩减时可能start = mid,当只有两个值的时候 ,左边的是start也是mid,会死循环,因此注意我们要让mid落在中间偏右的那个位置上。

找到答案所在行的二分搜索代码如下:

 static int BinarySearchRow(int[][] matrix, int target)
    {
        int start = 0;
        int end = matrix.length-1;
        while (start < end)
        {
            int mid = start + (end - start + 1) / 2;
            if (target < matrix[mid][0])
                end = mid - 1;
            else if (target > matrix[mid][0])
                start = mid ;
            else if (target == matrix[mid][0])
                return mid;
        }
        return start;
    }

找到答案的所在行之后,在当前行查找出答案,由于不会有重复值的情况,只要用最基础的准确查找就可以了。

找到指定行后,查找出所在位置的代码如下:

 static int BinnarySearch(int[] arr,int target)
    {
        int start = 0;
        int end = arr.length-1;
        while(start<=end)
        {
            int mid = start + (end - start) / 2;
            if (arr[mid]==target)
                return mid;
            else if(arr[mid]<target)
                start=mid + 1;
            else if(arr[mid]>target)
                end = mid - 1;
        }
        return -1;
    }

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!