剑指offer-面试题3 查找二维数组中的数

来源:互联网 发布:word for mac如何使用 编辑:程序博客网 时间:2024/06/05 19:25

面试题3 查找二维数组中的数

题目描述: 一个二维数组,每一行从左到右递增,每一列从上到下递增.输入一个二维数组和一个整数,判断数组中是否含有整数。

思路

这个二维数组是按方向有序的,也就是越往下越大,越往右越大,但是并不是严格类似于元素周期表的那种排列,第一行最后一个元素比第二行第一个元素要大的可能性是存在的。所以,想要找到二维数组中是否存在这个数,不能只是单独按行或者按列查找,而是两个方向都得兼顾。


这里写图片描述

上边的图代表的是一个二维数组。
其中的数和给定的数s比较时,更为一般的情况是④中的情况。通过简单的分析,我们能得出图上文字的结论。(其中边界问题应该讨论,但是后面的解决方法巧妙地避开了这个问题,所以不会专门去讨论)

Ⅰ.如果④大于给定的数s,那么它右下角D区域(包括边界)的数都大于s,如果s存在,它只可能存在于A,B,C三个区域中;
Ⅱ.如果④小于s,那么它左上角A区域(包括边界)的数都小于给定的数。如果s可能存在,它只可能存在于B,C,D三个区域中。
为了避免效率最低的逐行逐列查找,我们准备用以上两个总结出的数组中数的性质来设计一个更为高效合理的解法。
我们从①点,也就是第一行最后一列的数开始。分三种情况: (1)①==s;找到了,直接返回;
(2)① > s;符合Ⅰ,右下角包括边界,也就是①所在的列不再查找,列数col-1,沿着②方向继续查找;
(3) ① < s;符合Ⅱ,左上角包括边界,也就是①所在的行不再查找,行数row+1,沿着③方向继续查找。

通过这样的设计,我们就能较快地找到s是否存在于数组中了。思想分析清楚,代码也就水到渠成了。
ps:之前想到分别按行按列二分查找,但是没写出来……感觉自己想得太简单了。通过简单的分析,我们能得出的结论是

 每个块的左上角值是这个块的最小值,每个块的右下角是这个块的最大值。

现在假如:当②所在的列把数组分为两个数组块。简单的将s和每个块的最值比较,是有机会通过排除一些块从而减小s的判断范围的,但是例如分为a,b两个块之后,很有可能s满足

a_min<s<a_max  //a_mina_max是块a的最小值和最大值&&b_min<s<b_max  //b_min和b_max是块b的最小值和最大值

这样没有起到我们排除搜索范围提升性能的需求,但是这是一个不错的优化思路。以后有时间会深入思考下吧。
最后上个代码吧,这里参考了一下其它人的代码,整体还算可以,时间复杂度最好为O(1),最差为O(2n),平均为O(n),是可以接受的。

代码

public class Ex02SearchMatrix {     public static boolean searchMatrix(int[][] a, int s){        if (a==null)    return false;        int col = a[0].length-1;        //列数        int row = 0;                    //行数        while(col>=0 && row<a.length){            if (a[row][col]==s) return true;            if (a[row][col]>s)                      col--;            else                row++;              }        return false;       }}       

代码中的方法返回类型为boolean型。其中传入了两个变量,第一个是要判断的二维数组a,另一个是要找的数s。
代码的逻辑就是通过判断右上角的数跟s的大小,逐渐选出一条路来,最终找到s是否在数组中。查找算法还没看到,之后学到会在这儿进行补充。

转载请注明原文地址:http://blog.csdn.net/pomony1/article/details/64660698

0 0
原创粉丝点击