74. 搜索二维矩阵

174 阅读1分钟

方法三(最好的):TC为O(logmn)的解法,把矩阵当作一个一维有序数组来二分查找

  • 充分利用题目给定的矩阵特性。
  • 关键在于一维二维坐标的转化
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length, n = matrix[0].length;
        int left = 0, right = m * n - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            int i = mid / n, j = mid % n; // 二维坐标转为一维
            if (matrix[i][j] == target) {
                return true;
            } else if (matrix[i][j] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return false;
    }
}

方法二:TC为O(logm + logn)的解法,行、列分别二分查找

思路:逐渐缩小要查找的tar的范围。

  • 对列尾元素进行二分,以确定接下来要搜索的行。
  • 在找出来的行中再二分。
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix[0].length;
        int n = matrix.length;
        int row = Integer.MIN_VALUE;//待找的那一行

        //二分查找,确定下一步要查找的行
        int low1 = 0;
        int high1 = n - 1;
        while (low1 <= high1) {
            int mid = low1 + (high1 - low1) / 2;
            if (matrix[mid][m - 1] == target || matrix[mid][0] == target) {
                return true;
            } else if (matrix[mid][m - 1] > target && matrix[mid][0] < target) {
                row = mid;//某一行中,tar小于最后一个数,大于第一个数,找到那一行了
                break;
            } else if (matrix[mid][m - 1] < target) {
                low1 = mid + 1;
            } else {
                high1 = mid - 1;
            }
        }

        //没找到对应的行,直接false
        if (row == Integer.MIN_VALUE) {
            return false;
        }

        //在具体的行中再二分查找target
        int low2 = 0; 
        int high2 = m - 1;
        while (low2 <= high2) {
            int mid = low2 + (high2 - low2) / 2;
            if (matrix[row][mid] == target) {
                return true;
            } else if (matrix[row][mid] < target) {
                low2 = mid + 1;
            } else {
                high2 = mid - 1;
            }
        }
        return false;
    }
}
  • 典型错误: 忘了break造成死循环

image.png

暴力法:TC为O(mn)

方法一:TC为O(m + n)的解法

思路:逐渐缩小要查找的tar的范围。

  • 先线性遍历列的头元素/尾元素,以确定接下来要搜索的行。
  • 在找出来的行中搜索。
// TC为 O(m + n)解法
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix[0].length;
        int n = matrix.length;
        if (target < matrix[0][0] || target > matrix[n - 1][m - 1]) {
            return false;
        }
        //遍历每行头元素,确定下一步要遍历的行。
        int i = 0;
        while (i < n) {//这里选的时头元素,不太好,得特殊处理最后一行。
            if (i == n - 1 && target >= matrix[i][0]) {
                break;
            } else if (target >= matrix[i][0] && target < matrix[i + 1][0]) {
                break;
            }
            i++;
        }
        //遍历找出的那一行。
        for (int j = 0; j < m; j++) {
            if (matrix[i][j] == target) {
                return true;
            }
        }
        return false;
    }
}