剑指offer:二维数组的查找

剑指offer:二维数组的查找

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

思路:
1.首先可以判断该问题最差的算法是O(n^2),所以比这个方法更差的方法就不用考虑了。
2.其次可以想到可以用到 广度优先搜索(BFS) 算法。
3.最后是书上提供的思路,让人拍案叫绝:
右上方的点具有很好的性质,它左边的点都比它小,它下边的点都比它大。
所以,如果 target < 该点,那么可以排除整个一列,如果 target > 该点,那么可以排除整个一行 的点。更好的是,排除一行(或一列)后的矩阵的右上方的点仍然具有该性质。
如图所示:
从矩阵中查找7.查找 7

实现

BFS

这个方法更加通用一些,已经在牛客网通过。

class Solution {
public:
    struct Point
    {
        int row;
        int column;
    };
    //建立队列Q 
    queue<Point> Q;
    bool Find(int target, vector<vector<int> > array){
        int row = array.size();
        int column = array[0].size();
        vector<vector<bool> > mark(row);
        for (int i = 0; i < row; i++)
        {
            mark[i].resize(column);
        }
        for (int i = 0; i < row; i++){
             for (int j = 0; j < column; j++){
                 mark[i][j] = false;             //false 表示当前没有被扩展
             }
         }
        //异常 
        if (row == 0|| column == 0) return false;
        //比最小的小,比最大的大,则肯定没有 
        if (target < array[0][0] || target > array[row - 1][column - 1]) return false;
        Point first;
        first.row = 0;
        first.column = 0;
        Q.push(first);
        mark[0][0] = true;
        while(Q.empty() == false)
        {
    	    Point now = Q.front();           //Q.front()是将队列最前面的值赋给now,并没有剔除队列,还需要pop
            Q.pop();
            if (target == array[now.row][now.column]) return true;
            else if (target < array[now.row][now.column]) continue;       //从Q中剩下的继续进行扩展
            else                                                          //可以向右向下进行扩展
            {
                int row_down = now.row + 1;
                int column_right = now.column + 1;
                Point now_right, now_down;                                //now_right,now_down表示当前的结点的右边和下边
                if (column_right < column && mark[now.row][column_right] == false){
                    now_right.row = now.row;
                    now_right.column = column_right;
                    Q.push(now_right);
                    mark[now.row][column_right] = true;
                }
                if (row_down < row && mark[row_down][now.column] == false)
                {
                    now_down.row = row_down;
                    now_down.column = now.column;
                    Q.push(now_down);
                    mark[row_down][now.column] = true; 
                }
            }
       }
       return false;
   }
};  

注意:
1.值得关注的是如何使用vector建立二维数组,并且定义的时候要注意
vector<vector<int> > array
两个’>'之间要有一个空格。
2.还要注意的是要考虑各种极端情况,如矩阵的行和列都是1等。

书上的方法

在看懂前面的思路3的基础上,比较好实现,已经通过牛客网验证。

class Solution {
public:
   bool Find(int target, vector<vector<int> > array){
       int row = array.size();
       int column = array[0].size();
       //right_row, right_column 记录当前的右上角点的行列坐标。
       int right_row = 0;
       int right_column = column - 1;
       while(right_row < row && right_column >= 0)
       {
           if (target == array[right_row][right_column]) return true;
           else if (target < array[right_row][right_column])
           {
               right_column--;
           }
           else
           {
               right_row++;
           }
        }
        return false;
   }
};

注:同样的,位于左下角的点也具有这样的性质,当然也可以作为起始点。书上的思路是由简到难,当一个点位于矩阵中间的时候不好分析,但当位于边界的时候就好分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值