[路飞]_前端算法第一零九弹-搜索二维矩阵 II

125 阅读2分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战

编写一个高效的算法来搜索 *m* x *n* 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

示例 1:

图片.png

输入: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]], target = 5
输出:true

示例 2:

图片.png

输入: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]], target = 20
输出:false

直接查找

我们直接遍历整个矩阵 matrixmatrix,判断 targettarget 是否出现即可。

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        for (int[] row : matrix) {
            for (int element : row) {
                if (element == target) {
                    return true;
                }
            }
        }
        return false;
    }
}

复杂度分析

  • 时间复杂度:O(mn)O(mn)
  • 空间复杂度:O(1)O(1)

二分查找

由于矩阵 matrixmatrix 中每一行的元素都是升序排列的,因此我们可以对每一行都使用一次二分查找,判断 targettarget 是否在该行中,从而判断 targettarget 是否出现。

var searchMatrix = function(matrix, target) {
    for (const row of matrix) {
        const index = search(row, target);
        if (index >= 0) {
            return true;
        }
    }
    return false;
};

const search = (nums, target) => {
    let low = 0, high = nums.length - 1;
    while (low <= high) {
        const mid = Math.floor((high - low) / 2) + low;
        const num = nums[mid];
        if (num === target) {
            return mid;
        } else if (num > target) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    return -1;
}

复杂度分析

  • 时间复杂度:O(mlogn)O(mlog⁡n)。对一行使用二分查找的时间复杂度为 O(logn)O(log⁡n),最多需要进行 m 次二分查找。
  • 空间复杂度:O(1)O(1)

Z 字形查找

我们可以从矩阵 matrixmatrix 的右上角 (0,n−1)(0, n-1)(0,n−1) 进行搜索。在每一步的搜索过程中,如果我们位于位置 (x,y)(x,y),那么我们希望在以 matrixmatrix 的左下角为左下角、以 (x,y)(x,y) 为右上角的矩阵中进行搜索,即行的范围为 [x,m1][x,m−1],列的范围为 [0,y][0,y]

  • 如果 matrix[x,y]=targetmatrix[x,y]=target,说明搜索完成;
  • 如果 matrix[x,y]>targetmatrix[x,y]>target,由于每一列的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 y 列的元素都是严格大于 targettarget 的,因此我们可以将它们全部忽略,即将 y 减少 1;
  • 如果 matrix[x,y]<targetmatrix[x,y]<target,由于每一行的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 x 行的元素都是严格小于 targettarget 的,因此我们可以将它们全部忽略,即将 x 增加 1。

在搜索的过程中,如果我们超出了矩阵的边界,那么说明矩阵中不存在 targettarget

var searchMatrix = function(matrix, target) {
    const m = matrix.length, n = matrix[0].length;
    let x = 0, y = n - 1;
    while (x < m && y >= 0) {
        if (matrix[x][y] === target) {
            return true;
        }
        if (matrix[x][y] > target) {
            --y;
        } else {
            ++x;
        }
    }
    return false;
};