一、题目描述
难易程度:中等
在一个 n * m 的二维数组中,每一行都按照从左到右递增排序,每一列也按照从上到下递增排序。给定一个数,判断这个数是否在该二维数组中。
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.
二、解题思路
标志数法
若使用暴力法遍历矩阵 matrix ,则时间复杂度为 O(NM) 。暴力法未利用矩阵 “从上到下递增、从左到右递增” 的特点,显然不是最优解法。
我们发现:左下角元素 18 有一个特点,上面的数都比它小,右边的元素都比它大,符合这样规律的数字本题解中称为标志数。(右上角元素 15 也是标志数)
以 matrix 中的 左下角元素 为标志数 flag ,则有:
- 若 flag > target ,则 target 一定在 flag 所在 行的上方 ,即 flag 所在行可被消去。
- 若 flag < target ,则 target 一定在 flag 所在 列的右方 ,即 flag 所在列可被消去。
根据这个规律,得出算法流程:
-
从矩阵 matrix 左下角元素(索引设为 (i, j) )开始遍历,并与目标值对比:
-
若行索引或列索引越界,则代表矩阵中无目标值,返回 false 。
复杂度分析
时间复杂度:O(M+N) ,其中,N 和 M 分别为矩阵行数和列数,此算法最多循环 M+N 次。
空间复杂度:O(1) , i, j 指针使用常数大小额外空间。
三、代码实现
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
int i = matrix.length - 1, j = 0; // 左下角标志数
while(i >= 0 && j < matrix[0].length)
{
if(matrix[i][j] > target) i--;
else if(matrix[i][j] < target) j++;
else return true;
}
return false;
}
}
封面
今日算法系列,题解更新地址:studeyang.tech/2023/0714.h…