剑指Offer总结——二维数组的查找

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        if (array.size() == 0) {
            return false;
        }
        int rows = array.size();
        int cols = array[0].size();
        int j = cols - 1;
        int i = 0;
        while(i < rows && j >= 0) {
            if(array[i][j] < target) {
                ++i;
            }
            else if(array[i][j] > target) {
                --j;
            }
            else{
                return true;
            }
        }
        return false;
    }
};

这题思路很简单,我们先看一下题目:

重点就是每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。我们的思路可以是这样开始的:

  1. 直接从0到行末,从第一行到最后一行进行遍历
  2. 每次都拿出一个数字来和目标进行比较,如果找到了就返回true
  3. 当遍历到末尾后,还没有发现目标,那么就返回false

这样是可以的,但是当二维数组非常大的时候耗费的时间就会很大(时间复杂度大概在n^2,前提是二维数组近似方形且目标较靠后),不一定能够满足题目的要求,所以我们要根据上面画的重点来进行优化:

  1. 首先,可以确定的是行末,即最右边的数字,就是这一行最大的数字,因此,如果我们发现我们的目标比这个数字大就可以直接跳到下一行进行比对
  2. 如果最右边的数字比目标大,那么可以确定我们要找的目标只能是在左边或者下面,我们先考虑走到左边找目标数字的情况
  3. 当我们走到左边的时候,只会有两种情况,当前数字仍然比目标数字要大,以及比目标数字小,如果是比目标数字大,则我们继续向左走,最终情况会变回到后一种情况,即比目标数字小(如果都比目标数字大,那么可以确定已经没有可以比较的数字了,因为如果往下走,则可以发现下面的数字都比当前大,因为“每一列都按照从上到下递增的顺序排序”,而如果往上走,因为我们之前通过和上一行最大的数字比对,确定上一行的数字都比目标数字小,所以目标数字肯定不在上一行,因此可以直接结束掉循环,返回false
  4. 因为上一次比对的数字比目标数字小,因此我们直接向下走,不需要退回到下一行的行末,因为我们可以确定下一行的数字分别比上一行同一列的数字大,所以可以确定此时右侧的数字都比当前数字要大(因为目标数字比上一行的右侧的数字要小,而当前行右侧的数字又比上一行的同列的数字大),然后我们回到和情况2相似的步骤,发现比目标大则左移动,比目标小则向下移动……

总结一下,我们需要做的事情就是:

  1. 从最上面一行,最右侧开始比较,大了向左移动,小了向下移动
  2. 当遍历到比最左侧要左,比最下面一行要下(即超出边界)的时候,就断掉循环,返回false
原文地址:https://www.cnblogs.com/yejianying/p/jianzhioffer_2d_array_searching.html