托普利茨矩阵 图解题解
这道题到底在问什么
- 输入
- matrix = [[1,2,3,4],[5,1,2,3],[9,5,1,2]]
- 输出
- true
- 解释
- 每条左上→右下的斜线上数字都一样(如 1,1,1 / 2,2 / 5,5)。
先想最直接的笨办法
代码极简:两层循环从 (1,1) 扫到右下角,发现任何一格不等于它的左上角就立即 return false;全都相等就 return true。第一行、第一列因为没有左上角,从下标 1 开始循环就自然跳过了。(动画第 27 步)
最优解:一步一步想明白
- 33 行 4 列这是我们的例子。先肉眼找几条对角线感受一下:左上那条 1→1→1、它右边一条 2→2→2、左下那条 5→5。要判断的就是:是不是每条斜线都这样「一路同值」。
- 4真的去走每一条对角线最直白的想法:找出所有对角线的起点(第一行、第一列的格子),每条都顺着右下方走一遍,逐个比是不是相等。这能做,但要专门处理「哪些是起点、怎么往右下走」,写起来有点绕。
- 5别走对角线,只看左上邻居换个角度:对角线就是「右下方向」,那么一个格子在它对角线上的前一个,就是它的左上角那格 (i-1, j-1)。所以只要每个格子都等于自己的左上角,整条对角线自然就全相等了——根本不用真的走斜线!
- 6逐格相等 = 整条相等如果 a 等于它的左上 b,b 又等于它的左上 c……那 a=b=c=… 整条线就都相等了。所以我们不必整条线一起看,只需逐格检查「我 == 我的左上角」。第一行、第一列没有左上角,直接跳过。
- 7第一行/第一列没有左上角,跳过蓝色这些是第一行和第一列——它们没有左上角,不用检查(它们各自是某条对角线的起点)。真正要逐个验证的,是从 (1,1) 开始、行列都 ≥1 的格子。
- 81 == 1 ✓看 (1,1) 这格(紫色),它的值是 1;它的左上角是 (0,0),值也是 1。1 == 1,相等,这格通过。
- 9已检查 1 格(1,1) 检查通过,标成蓝色「已确认」。继续看它右边的格子。
- 102 == 2 ✓看 (1,2),值是 2;它的左上角 (0,1) 也是 2。两格同时高亮(紫色)——2 == 2,相等,通过。
- 11已检查 2 格(1,2) 也通过,变蓝锁定。已经确认了 2 格,继续往右看 (1,3)。
- 123 == 3 ✓(1,3) 值 3,它的左上角 (0,2) 也是 3。3 == 3,通过。第二行三个待查格子全过了。
- 13已检查 3 格第二行从 (1,1) 到 (1,3) 都通过了(蓝色)。注意我们一直只在比「自己 vs 左上角」,从没真的去走整条斜线,但效果完全一样。接着检查第三行。
- 145 == 5 ✓进入第三行。(2,1) 值 5,它的左上角 (1,0) 也是 5。5 == 5,通过。
- 15已检查 4 格(2,1) 变蓝锁定。这格落在左下那条 5→5 的对角线上,与上一格 (1,0) 的 5 一脉相承。继续看 (2,2)。
- 161 == 1 ✓(2,2) 值 1,左上角 (1,1) 也是 1。1 == 1,通过。这一格刚好在那条「1→1→1」的主对角线上。
- 17已检查 5 格(2,2) 锁定。只剩最后一格 (2,3) 还没查了。
- 182 == 2 ✓最后一格 (2,3) 值 2,左上角 (1,2) 也是 2。2 == 2,通过。所有该查的格子都查完了。
- 196 格全相等 → true6 个待查格子全部「等于自己的左上角」,没有任何一处不相等,所以这是托普利茨矩阵,返回 true。我们只扫了一遍矩阵就判完了。
- 20逐格相等 = 整条相等回头看这条主对角线 (0,0)→(1,1)→(2,2),值是 1,1,1。我们之所以确定它全相等,靠的就是「(1,1)=左上(0,0)」和「(2,2)=左上(1,1)」这两次逐格比较串起来的。
- 21同样靠逐格传递确认再看 (0,1)→(1,2)→(2,3) 这条,值是 2,2,2,也全相等。每一条对角线都是被「相邻两格的逐个比较」悄悄验证过的——这就是这个技巧的妙处。
- 22短对角线也一样成立(1,0)→(2,1) 这条短对角线值是 5,5,靠 (2,1)=左上(1,0) 这一次比较确认。短到只有两格的对角线,逻辑完全一样。
- 23单格对角线天然成立左下角的 9 和右上角的 4 各自是一条只有一个格子的对角线,无需比较、天然成立。这也解释了为什么第一行、第一列不用查——它们都是对角线的起点。
- 24只要有一格 ≠ 左上,就 false再看一个反例 [[1,2],[2,2]]。它的对角线 (0,0)→(1,1) 应该全相等才行。我们用同样的方法,逐格检查一下。
- 252 ≠ 1 ✗在 [[1,2],[2,2]] 里检查 (1,1),它的值是 2;它的左上角 (0,0) 是 1。2 ≠ 1,不相等!对角线 (0,0)→(1,1) 上出现了不一样的数(红色)。
- 26发现一处不等即可结束只要任意一格不等于它的左上角,就说明那条对角线不是同值,整个矩阵就不是托普利茨矩阵。立刻返回 false,根本不用再看后面的格子。
- 27双层循环 + 一个判断代码极简:两层循环从 (1,1) 扫到右下角,发现任何一格不等于它的左上角就立即 return false;全都相等就 return true。第一行、第一列因为没有左上角,从下标 1 开始循环就自然跳过了。
- 30记住这一句把「整条对角线都相等」这个全局条件,转化成「每个格子都等于自己左上邻居」这个局部条件——这是很多矩阵题的通用思路:用相邻关系替代远距离关系。
⚠️ 容易写错的地方
✗ 错:循环从 i=0,j=0 开始
✓ 对:从 i=1,j=1 开始
第一行第一列没有左上角,访问 matrix[-1][-1] 会越界或比错
✗ 错:真的去走每条对角线、分类讨论起点
✓ 对:只比「自己 vs 左上角」
逐格比较等价且代码简洁,无需处理起点在上边还是左边
✗ 错:发现不等还继续扫完
✓ 对:发现一处不等立即 return false
一处违反整体就 false,提前返回更快(不影响正确性但更优)
完整代码(Python / C++ / Java)
Python
class Solution:
def isToeplitzMatrix(self, matrix):
m, n = len(matrix), len(matrix[0])
for i in range(1, m):
for j in range(1, n):
if matrix[i][j] != matrix[i - 1][j - 1]:
return False
return TrueC++
class Solution {
public:
bool isToeplitzMatrix(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][j] != matrix[i - 1][j - 1]) {
return false;
}
}
}
return true;
}
};Java
class Solution {
public boolean isToeplitzMatrix(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][j] != matrix[i - 1][j - 1]) {
return false;
}
}
}
return true;
}
}复杂度
时间
O(m·n)
每个格子最多比较一次,最坏扫完整张图
空间
O(1)
只用几个下标变量,不开额外数组
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 托普利茨矩阵 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
如果矩阵特别大、内存只能一次读一行(无法整体放进内存)怎么办?+
只需保留「上一行」即可:读当前行时,逐列比较 cur[j] 是否等于 prev[j-1],比完后让 prev = cur。这样空间从 O(mn) 降到 O(n),是这题的经典 follow-up。
为什么不需要单独处理第一行和第一列?+
它们是各条对角线的起点,没有左上角可比。让循环从下标 1 开始,它们自然被跳过,不需要任何特判。
能用 (i-j) 是否相同来分组对角线吗?+
可以。同一条对角线上的格子,i-j 的值相同。可以用哈希表按 i-j 分组、检查每组是否同值,但那样要额外空间,远不如逐格比左上角简洁。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 托普利茨矩阵 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。