从一个部分有序的二维矩阵中查找指定值

1,283 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

题目

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

从下列矩阵中, 查找数字7, 有则返回true; 没有则返回false.

matrix

自己的思路

当看到这个题目时, 我脑瓜里跳出的想法是可以从矩阵的对角线上入手, 拿当前对角线上的值与要查找的目标值进行比较, 如果相等, 则返回true; 如果该值大于查找值, 则应该在当前位置的上边或者左边; 如果该值小于查找值, 则查找值应该在当前位置的下边或者右边.

出现的问题

假设该矩阵是一个方形矩阵, 而且对角线的值大于查找值, 在这种情况下, 需要在当前行中向左遍历和在当前列中向上遍历.

如果该矩阵不是一个方形矩阵, 那么遇到的问题就更加复杂了.

随着遍历对角线的次数, 问题规模并没有大幅度减小, 而且还要处理非方形矩阵的情况, 所以当前思路想到这里的时候, 我就放弃了.

比较好的思路

  1. 从右上角进行作为切入点, 如果当前位置的值是我们的查找值, 则返回true.
  1. 如果当前位置的值小于查找值, 则表明当前行所有的值都是小于查找值的, 进向下移动一行进行查找.
  1. 如果当前位置的值大于查找值, 则表明当前列所有的值都是大于查找值的, 则向左移动一列进行查找.
  2. 重复1, 2, 3步, 进到找到查找值, 返回true; 或者遍历完当前矩阵没有找到查找值, 返回false.

当然也可以从左下角作为切入点, 原理同上.

代码

以右上角作为切入点

 private boolean searchDstFromRightTop(int[][] list, int dst) {
 ​
     // 边界判断
     if (list == null || list.length == 0 || list[0].length == 0) {
         return false;
     }
 ​
     int rows = list.length;
     int cols = list[0].length;
 ​
     // 以右上角作为切入点, 因此坐标为第0行, 列为总列数-1列
     int row = 0;
     int col = cols - 1;
 ​
     // 循环条件: 最大行数为总行数-1, 最小列数为0
     while (row < rows && col >= 0) {
 ​
         // 如果当前值为查找值, 则返回true
         if (list[row][col] == dst) {
             return true;
         } else if (list[row][col] > dst) { // 如果当前值大于查找值, 则列数-1, 继续查找
             System.out.println("col--, row: " + row + ", col: " + col);
             col--;
         } else { // 如果当前值小于查找值, 则行数+1, 继续查找
             System.out.println("row++, row: " + row + ", col: " + col);
             row++;
         }
     }
 ​
     return false;
 }

以左下角作为切入点

 private boolean searchDstLeftBottom(int[][] list, int dst) {
 ​
     // 边界判断
     if (list == null || list.length == 0 || list[0].length == 0) {
         return false;
     }
 ​
     // 总行数
     int rows = list.length;
 ​
     // 总列数
     int cols = list[0].length;
 ​
     // 以左下角作为切入点, 因此坐标为总行数-1行, 第0列
     int row = rows - 1;
     int col = 0;
 ​
     // 循环条件: 最小行数为第0行, 最大列为总列数-1列
     while (col < cols && row >= 0) {
 ​
         // 如果当前值为查找值, 则返回true
         if (list[row][col] == dst) {
             return true;
         } else if (list[row][col] > dst) { // 如果当前值大于查找值, 则行数-1, 继续查找
             System.out.println("col--, row: " + row + ", col: " + col);
             row--;
         } else { // 如果当前值小于查找值, 则列表+1, 继续查找
             System.out.println("row++, row: " + row + ", col: " + col);
             col++;
         }
     }
 ​
     return false;
 }

总结

解决本题需要了解数组的各种特性以及分析问题的能力. 也就是将复杂问题化解为简单问题的能力, 将抽象问题化解为具体问题的能力.

当我们需要解决一个复杂的问题时候, 应该从一个具体的问题入手, 通过分析简单具体的问题, 来寻找普遍的规律.