一、题目描述
题目链接:leetcode.cn/problems/er…
难易程度:中等
在一个 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
,则有:
根据这个规律,得出算法流程:
从矩阵 matrix 左下角元素(索引设为 (i, j) )开始遍历,并与目标值对比:
- 当 matrixi > target 时,执行 i-- ,即消去第 i 行元素;
- 当 matrixi < target 时,执行 j++ ,即消去第 j 列元素;
- 当 matrixi = target 时,返回 true ,代表找到目标值。
若行索引或列索引越界,则代表矩阵中无目标值,返回 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 target) i--;
else if(matrix[i][j] < target) j++;
else return true;
}
return false;
}
}
封面
今日算法系列,题解更新地址:studeyang.tech/2023/0714.h…