栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

[剑指offer刷题04] - 二维数组中的查找

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

[剑指offer刷题04] - 二维数组中的查找

题目(题目及部分解法来源于力扣)

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

solution one:

双重for循环遍历每个元素,判断数组是否含有该数组。但这种方法基本忽略题目所给信息。 solution two:

题目中说:每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。这句话怎么理解?可以这样看:给定整数target,假设当前搜索到a行b列,如果 target < arr[a][b+1] ,说明b列后面的数字都要大于target。此时可以停止搜索所在行。此时在意a行b列作为起点,搜索b列中是否有target,但也需要判断,如果arr[a + 1][b] > target ,就说明所在列后面都大于target,就不用继续遍历所在列了。

 public static boolean findNumberIn2DArray1(int[][] matrix, int target) {
         if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {  //先判断数组是否为空
            return false;
        }
        int rows = matrix.length;
        int cols = matrix[0].length;
        for(int i = 0 ; i < rows; ++i)
        {
            for(int j = 0 ; j < cols; ++j)
            {
                if(matrix[i][j] == target)  return true;
                if( (j + 1 == cols) || (matrix[i][j + 1] > target) )
                {
                    for(int k = i; k < rows; ++k)
                    {
                        if(matrix[k][j] == target) return true;
                       if( (k + 1 == len1) || (matrix[k+1][j] > target)) break;   (1)
                    }
                }
            }
        }
        return false;
    }

下面这部分是为了复习[剑指offer刷题03]中学过HashSet,solution two和[剑指offer刷题03]中学过HashSet都懂得同学,可直接看solution three.
如果去掉solution two中语句(1)就会有个漏洞,就是可能会重复搜索所在列。例如:下面这个矩阵,如果搜索18的话,按照上面的思路,由于第二行19大于18,所以会搜索第4列的12、16、17、26。而在第三行,22大于18,会搜索第四列剩余元素16、17、26。这样就造成重复搜索。
所以我们在下面的方法程序中利用[剑指offer刷题03]中学过HashSet。由于HashSet中的元素不会重复,所以只要将访问过的列放入HashSet中后,下一次判断要循环的列是否在HashSet中即可。

改进代码:

    public static boolean findNumberIn2DArray2(int[][] matrix, int target) {
        HashSet sets = new HashSet();  // 建立HashSet集合
		if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        int len1 = matrix.length;
        int len2 = matrix[0].length;
        for(int i = 0 ; i < len1; ++i)
        {
            for(int j = 0 ; j < len2; ++j)
            {
                if(matrix[i][j] == target)  return true;
                if( (j + 1 == len2) || (matrix[i][j + 1] > target) )
                {
                    if(sets.contains(j)) continue;  //判断HashSet中是否包含所在列
                    for(int k = i; k < len1; ++k)
                    {
                        if(matrix[k][j] == target) return true;
                    }
                    sets.add(j); //如果不包含target,则将遍历过的列加入到HashSet中
                }
            }
        }
        return false;
    }
solution three:

在solution two中,我们的方法是从二维数组左上角进行遍历的。换个角度,如果我们在二维数组右上角进行遍历的话,这样也是一种方法。如果当前元素大于目标值,说明当前元素的下边的所有元素都一定大于目标值,因此往下查找不可能找到目标值,往左查找可能找到目标值。如果当前元素小于目标值,说明当前元素的左边的所有元素都一定小于目标值,因此往左查找不可能找到目标值,往下查找可能找到目标值。

public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        int rows = matrix.length, columns = matrix[0].length;
        int row = 0, column = columns - 1;
        while (row < rows && column >= 0) {
            int num = matrix[row][column];
            if (num == target) {
                return true;
            } else if (num > target) {
                column--;
            } else {
                row++;
            }
        }
        return false;
    }

summary:相比solution two, solution three要简便的多,且代码看起来更整洁。所以有时候从反向的角度看待同一个问题,会有不同的结果,还是要学会让自己多角度看待问题。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/782188.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号