【leetcode】 74. 搜索二维矩阵

81 阅读2分钟

image.png

基础版

利用题目给定的特性,来进行查找
假定题目给定的target = 15,如果顺序查找(按照一行一行的查找,即可),这样效率太慢,没有利用题目的矩阵性质。
此时如果先确定行,然后再来进行查找,会节省时间。如果首先用每一行的行首来进行比较target,进而来确定行。
那么从上至下,从左至右来确定行首,是否可行?这样是不可以的,target = 15,此时我们无法确定第一行的末尾是否存在15或者比15更大的数字,所以行不通。那么我们可以从行尾来确定,target > 7,此时我们挪到下一行,此时target < 20,我们可以在这一行来进行查找。
下面的这种解法也是利用了这一特性,只不过是从最底端的行首来确定的。

var searchMatrix = function (matrix, target) {
    let row = matrix.length,
        col = matrix[0].length;
    for (let i = row - 1; i >= 0; --i) {
        for (let j = 0; j < col; ++j) {
            if (matrix[i][j] > target) {
                break;
            } else if (matrix[i][j] < target) {
                continue;
            } else {
                return true;
            }
        }
    }
    return false;
};

依据上面的结论,我们就可以利用二分法来确定行,进而确定列来达到提高效率的目的。

逐步查找

可以利用35题的结论来解决这一题
先查找适用的行,确定行之后,再在该行里面寻找适合插入的元素位置,最后将该位置与target比对即可

var searchMatrix = function (matrix, target) {
    if (!matrix.length || !matrix[0].length) return false;
    var binarySearch = function (nums) {
        let left = 0, right = nums.length - 1
        while (left <= right) {
            let mid = Math.floor((left + right) / 2)
            if (nums[mid] === target) {
                return mid
            } else if (nums[mid] > target) {
                right = mid - 1
            } else {
                left = mid + 1
            }
        }
        return left
    }
    let firstCol = []
    for (let i = 0; i < matrix.length; ++i) {
        firstCol.push(matrix[i][0])
    }
    // 查找适用的行
    let row = binarySearch(firstCol)
    // 确认行是否符合要求
    if (row >= matrix.length || matrix[row][0] > target) row--;
    if (row < 0) return false
    // 查找在该行里面适合插入的位置
    let insertIndex = binarySearch(matrix[row])
    // 比对与target的值
    return matrix[row][insertIndex] === target
};

更优雅的解法

var searchMatrix = function(matrix, target) {
    if (!matrix.length || !matrix[0].length) return false;

    let rows = matrix.length, cols = matrix[0].length;
    let left = 0, right = rows * cols - 1;

    while (left <= right) {
        let mid = Math.floor((left + right) / 2);
        let midElement = matrix[Math.floor(mid / cols)][mid % cols];

        if (midElement === target) {
            return true;
        } else if (midElement < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }

    return false;
};