LeetCode 240. Search a 2D Matrix II

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
Integers in each row are sorted in ascending from left to right.
Integers in each column are sorted in ascending from top to bottom.
For example,

Consider the following matrix:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]

Given target = 5, return true.
Given target = 20, return false.

题目要求为在一个二维矩阵中查找一个数,找到则返回true,否则返回false。
遇到查找的问题,我首先想到的是使用二分法。但是由于题目中的矩阵,虽然每一行每一列都是有序的,但是无法确定matrix[i+1][j]matrix[i][j+1]的大小关系,因此,考虑对这个二维矩阵拆分为两层一维,并分别使用二分法。首先,用一次二分法确定行的范围:

while (up <= down) {
    int mid = (up + down) / 2;
    if (target < matrix[mid][0]) {
        down = mid - 1;
    }
    else if (target > matrix[mid][0]) {
        up = mid + 1;
    }
    else {
        return true;
    }
}

之后得到的down即为行的下限,之后对第0行到第down行分别进行二分查找,即可得到答案。每一行的二分查找同理:

int left = 0, right = matrix[0].size() - 1;
while (left <= right) {
    int mid = (left + right) / 2;
    if (target < matrix[r][mid]) {
        right = mid - 1;
    }
    else if (target > matrix[r][mid]) {
        left = mid + 1;
    }
    else {
        return true;
    }
}

总体代码实现如下:

bool searchMatrix(vector<vector<int>>& matrix, int target) {
    // 先二分查找出行的下限
    int up = 0, down = matrix.size() - 1;
    if (matrix.empty() || matrix[0].empty()) {
        return false;
    }
    while (up <= down) {
        int mid = (up + down) / 2;
        if (target < matrix[mid][0]) {
            down = mid - 1;
        }
        else if (target > matrix[mid][0]) {
            up = mid + 1;
        }
        else {
            return true;
        }
    }
    // 再次使用二分法在筛选出的每一行查找目标
    for (int r = 0; r <= down; r++) {
        int left = 0, right = matrix[0].size() - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (target < matrix[r][mid]) {
                right = mid - 1;
            }
            else if (target > matrix[r][mid]) {
                left = mid + 1;
            }
            else {
                return true;
            }
        }
    }
    return false;
}

时间复杂度为O(nlogn),效率一般。
再换一种思路,从这个矩阵本身的特点出发。对于任意一个数matrix[i][j],难以对周围的数进行分割。但是对于两个特别的位置,matrix[n-1][0]matrix[0][n-1],如果用target和它们进行比较,是可以明确的排除掉某一行或这一列的。按照这个思路,假设从矩阵的左下角matrix[n-1][0]出发,先排除掉一行或者一列,再与剩余的matrix[n-2][0]或者matrix[n-1][1]比较,又可以去掉一行或一列,依次类推。实现如下:

bool searchMatrix(vector<vector<int>>& matrix, int target) {
    if (matrix.empty()) {
        return false;
    }
    int row = matrix.size() - 1, col = matrix[0].size() - 1;
    int r = row, c = 0;
    while (r >= 0 && c <= col) {
        if (target < matrix[r][c]) {
            r--;
        }
        else if (target > matrix[r][c]) {
            c++;
        }
        else {
            return true;
        }
    }
    return false;
}

这种看似简单粗暴的策略,时间复杂度不难得到,为O(n),还要优于二分的算法。

注意:
1. 由于题目输入包含空矩阵,所以无论哪一种方法,都要注意判断,防止越界。
2. 二分法不同实现的边界要确定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值