二维有序矩阵的查找

来源:互联网 发布:conoha绑定域名 编辑:程序博客网 时间:2024/05/21 10:37

A. 问题描述

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

B. 问题分析

其实笨方法有很多种啦:
* 全部无脑遍历一次,时间复杂度为O(NM)
* 对每行/列做二分查找,时间复杂度为O(Nlog M)
* 好像还不够好,可以整体用二分吗?

我们来看一个性质,对于一个N*M的如题所述的矩阵A,如果存在某个值等于要找的target值,看A的最右上角的元素key = A[0][M-1],从这个位置每步向左走或向下走,必定存在一条路径到达target。

所以关键是如何走出这样一条路径出来?

其实需要先对矩阵的性质有一个了解。如下图所示,注意区域2只有一个元素,就是当前矩阵的右上角的位置,很明显,区域1的所有值都是不大于key(即区域2的值),而区域4的所有值都是不小于key的,区域3的元素的值与key暂时没有明确的关系。

不过上面的性质已经足够加快很多了!!!
1. 如果target = key,那么就找到咯!
2. 比如发现target > key,那么明显区域1和2都没必要继续搜索了,对不对?现在需要搜索的矩阵变成了区域3和区域4组成的新的子矩阵了!!!
3. 反之,如果target < key,那么也很明显,区域2和区域4就没必要搜索了,接下来只需要搜索区域1和区域3组成的子矩阵即可!

所以,总的来说,这个算法的复杂度为O(N + M),应该能够很容易分析出来吧?
分析

C. 代码实现

class Solution {public:    bool Find(vector<vector<int> >& array, int target) {        if (array.empty())            return false;        int rowSize = array.size(), colSize = array[0].size();        int x = 0, y = colSize - 1;        while (check(0, rowSize, x) && check(0, colSize, y)) {            if (target == array[x][y])                return true;            else if (target < array[x][y])                --y;            else                ++x;        }        return false;    }    bool check(int lower, int upper, int now) {        return now >= lower && now < upper;    }};

D. 还有更快的算法吗?

应该是有的,不过有点复杂,思路是——在对角线上做二分查找,然后递归下去,这样的话,分治收敛得更快,有兴趣的可以实现出来交流一下,我等下次回来再实现。【未完待续】


参考:July的《编程之法》4.2节

0 0