矩阵对角线元素的和 图解题解
这道题到底在问什么
- 输入
- mat=[[1,2,3],[4,5,6],[7,8,9]]
- 输出
- 25
- 输入
- mat=[[5]]
- 输出
- 5
最优解:为什么这么做
一句话答案:LeetCode 1572 矩阵对角线元素的和:主对角线上行号等于列号、副对角线上行号加列号等于 n 减 1,两条逐行各取一格相加,n 为奇数时正中心被两条线共用只算一次,时间 O(n)、空间 O(1)。
对角线求和,到底要加哪些格子
给一个 n 行 n 列的正方形矩阵 mat,把它两条对角线上的元素加起来。主对角线是从左上角到右下角那条,副对角线是从右上角到左下角那条。题面例子是第一行 1、2、3,第二行 4、5、6,第三行 7、8、9 的方阵,答案 25;再小到 mat 只有一个数 5,答案就是 5。要留神两条对角线在正方形中间可能落到同一个格子上,题目要的是这个格子只算一次的和。
两条判定式,直接点到对角线上的格子
对角线上满打满算才 2n 个元素,把整张 n 乘 n 的表挨个格子扫一遍再挑,其余全是陪跑。好在对角线元素的位置有现成判定式:给一个格子记行号 i 和列号 j,它在主对角线上,当且仅当 i 等于 j;在副对角线上,当且仅当 i 加 j 等于 n 减 1。按行走,第 i 行里主对角线那格落在第 i 列,副对角线那格落在第 n 减 1 减 i 列,一步定位。唯一要当心两格会不会重合:当第 n 减 1 减 i 列正好等于第 i 列时,两条对角线在这行撞到一起,那格正是正方形的正中心,只有 n 是奇数才会发生,它在主对角线那趟已经加过,副对角线这趟就得跳过。
一趟循环,顺手把去重也做了
参考代码把它压成一趟循环。累加变量 ans 从零起,按行遍历:对第 i 行,先加上主对角线元素、即第 i 列的值;再令 j 等于 n 减 1 减 i,若 j 不等于 i,就把第 j 列的副对角线元素也加上;若 j 等于 i,说明撞上正中心、已经加过,直接跳过。走完 n 行,ans 就是答案,求和与去重一次遍历全办了。
拿题面这个 3 乘 3 矩阵手算一遍
还是第一行 1、2、3、第二行 4、5、6、第三行 7、8、9 这个矩阵,n 是 3。先走主对角线:第 0 行取 1,第 1 行取 5,第 2 行取 9,和是 1 加 5 加 9 等于 15。再走副对角线,n 减 1 是 2:第 0 行取第 2 列的 3;第 1 行副对角线列 n 减 1 减 1 还是第 1 列,和主对角线撞在一起、落在正中心 5,跳过不加;第 2 行取第 0 列的 7。
合起来 15 加 3 加 7 等于 25,正中心的 5 只算一次,和题面答案对得上。要是忘了去重、把中心的 5 再加一遍,就会从 25 错成 30,这是本题最常见的失分点。
偶数边长别多减,单格矩阵就是它自己
先说奇偶这道坎。n 是奇数时两条对角线在正中心交叉,那格必须去重;可 n 是偶数时,正中心落在四个格子正当中、不落到任何具体格子,两条线一个公共格都没有,八格各加一次,这时再减中心反而把答案算小了。副对角线下标是 j 等于 n 减 1 减 i,少减那个 1、写成 j 等于 n 减 i,整条对角线都会错位甚至越界。最小的边界是单格矩阵,n 是 1,那个数既在主对角线又在副对角线正中心上,只算一次,答案就是它本身,也就是题面第二个例子里那个 5。
复杂度上,全程按行走一遍、每行最多看两个格子,最多 2n 个、跟边长成正比,时间 O(n),不必扫整张 n 乘 n 的表;空间上只用一个累加变量,空间 O(1)。
▶ 动画逐步走查(共 27 步)——想跟着动画一帧帧对照就展开
- 3把这两条判定式刻进脑子:主对角线 i 等于 j,副对角线 i 加 j 等于 n 减 1。两条都加,奇数边长时正中心多算了一次要减回来。下面每一帧都在套这两条式子,先从 3 行 3 列、从主对角线开始走。
- 4橙 = 正在看的格,蓝 = 已计入对角线和这是 3 行 3 列的矩阵。先走主对角线,也就是行号等于列号的那条:位置 (0,0)、(1,1)、(2,2),从左上到右下。右边面板记累加过程,现在和是 0。
- 5行号 0 等于 列号 0,在主对角线上看主对角线上的格子 (0,0),行号 0 和列号 0 相等,确实在主对角线上,它的值是 1。
- 6主对角线和累计 1把 1 加进对角线和,这一格变蓝表示已经计入,和现在是 1。主对角线还没走完,接着看下一格。
- 7行号 1 等于 列号 1,在主对角线上看主对角线上的格子 (1,1),行号 1 和列号 1 相等,确实在主对角线上,它的值是 5。
- 8主对角线和累计 6把 5 加进对角线和,这一格变蓝表示已经计入,和现在是 6。主对角线还没走完,接着看下一格。
- 9行号 2 等于 列号 2,在主对角线上看主对角线上的格子 (2,2),行号 2 和列号 2 相等,确实在主对角线上,它的值是 9。
- 10主对角线和累计 15把 9 加进对角线和,这一格变蓝表示已经计入,和现在是 15。主对角线三格全加完了。
- 111 加 5 加 9 等于 15主对角线 1、5、9 都加完了,和是 15。接下来走副对角线,也就是行号加列号等于 n 减 1 的那条;这里 n 是 3,所以是 i 加 j 等于 2,位置 (0,2)、(1,1)、(2,0),从右上到左下。
- 12行号 0 加 列号 2 等于 2看副对角线上的格子 (0,2),行号 0 加列号 2 等于 2,正好是 n 减 1,在副对角线上,值是 3。
- 13副对角线累加中 · 和 18它不是正中心,放心加。把 3 加进和,这一格变蓝,和现在是 18。
- 14行号 1 加 列号 1 等于 2看副对角线上的格子 (1,1),行号 1 加列号 1 等于 2,正好是 n 减 1,在副对角线上,值是 5。不过要小心,这一格行号也等于列号。
- 15n 是奇数,正中心只算一次这一格 (1,1) 行号等于列号、又满足 i 加 j 等于 2,正是矩阵的正中心,它在主对角线那趟已经把 5 算过一次了。n 是 3 这种奇数,两条对角线在正中心交叉,为了不重复,这一趟把它标红跳过,不再加,和还是 18。
- 16行号 2 加 列号 0 等于 2看副对角线上的格子 (2,0),行号 2 加列号 0 等于 2,正好是 n 减 1,在副对角线上,值是 7。
- 17副对角线累加中 · 和 25它不是正中心,放心加。把 7 加进和,这一格变蓝,和现在是 25。
- 18主 15 + 副 3 与 7,中心 5 只算一次 = 25两条对角线都走完了。主对角线 1、5、9,副对角线又加了 3 和 7,正中心的 5 只算了一次。一共五个格子,1 加 5 加 9 加 3 加 7 等于 25,这就是答案。注意如果不去重,把中心 5 多加一次,就会错成 30。
- 19看看 n 是偶数时有没有正中心再看一个 4 行 4 列的矩阵,n 是 4,是偶数。还是加两条对角线,留意一下它和刚才 3 乘 3 有什么不一样。先走主对角线,i 等于 j,位置 (0,0)、(1,1)、(2,2)、(3,3)。
- 20主对角线累加 · 和 1主对角线格子 (0,0) 值是 1,行号等于列号,加进和,和到 1。
- 21主对角线累加 · 和 7主对角线格子 (1,1) 值是 6,行号等于列号,加进和,和到 7。
- 22主对角线累加 · 和 18主对角线格子 (2,2) 值是 11,行号等于列号,加进和,和到 18。
- 23主对角线累加 · 和 34主对角线格子 (3,3) 值是 16,行号等于列号,加进和,和到 34。主对角线四格加完,和 34。
- 24副对角线累加 · 和 38副对角线格子 (0,3) 值是 4,行号 0 加列号 3 等于 3,在副对角线上,加进和,和到 38。
- 25副对角线累加 · 和 45副对角线格子 (1,2) 值是 7,行号 1 加列号 2 等于 3,在副对角线上,加进和,和到 45。
- 26副对角线累加 · 和 55副对角线格子 (2,1) 值是 10,行号 2 加列号 1 等于 3,在副对角线上,加进和,和到 55。
- 27副对角线累加 · 和 68副对角线格子 (3,0) 值是 13,行号 3 加列号 0 等于 3,在副对角线上,加进和,和到 68。副对角线四格也加完了。
- 28n 偶数,两条对角线不相交关键的不一样在这里:n 等于 4 是偶数,正中心落在四个格子正中间,不是某一个具体格子,所以两条对角线一个公共格子都没有,八个格子互不重叠,各加一次就好,不用减谁。这正是奇数和偶数边长的区别。
- 29主 34 + 副 34 = 68(无去重)八个格子全加完,主对角线 1、6、11、16 是 34,副对角线 4、7、10、13 也是 34,没有重叠不用减,合计 68。对比 3 乘 3 那次要减中心,这次干干净净,这就是边长奇偶带来的差别。
⚠️ 容易写错的地方
✗ 错:n 是奇数时把正中心加了两次
✓ 对:正中心同时在两条对角线上,只能算一次,要减掉一次或在副对角线那趟跳过它
本例 3 乘 3 的正中心 5 若不去重,答案会从 25 错成 30,这是这道题第一大坑
✗ 错:副对角线下标算错,写成 j 等于 n 减 i
✓ 对:副对角线是 i 加 j 等于 n 减 1,所以 j 等于 n 减 1 减 i
少减了 1 会整条对角线错位、甚至下标越界,务必记牢 n 减 1
✗ 错:n 是偶数时也去画蛇添足地减中心
✓ 对:偶数边长两条对角线没有公共格子,不存在重复,不能减
本例 4 乘 4 八个格子互不重叠,误减会让答案偏小
✗ 错:以为要把整个矩阵扫一遍才能求和
✓ 对:只走两条对角线就够,时间 O(n) 而不是 O(n 的平方)
对角线元素的位置由 i 和 j 的关系直接定位,不需要遍历每个格子
完整代码(Python / C++ / Java)
Python
from __future__ import annotations
from typing import *
from collections import *
from functools import *
from itertools import *
from math import *
from heapq import *
from bisect import *
class Solution:
def diagonalSum(self, mat: List[List[int]]) -> int:
ans = 0
n = len(mat)
for i, row in enumerate(mat):
j = n - i - 1
ans += row[i] + (0 if j == i else row[j])
return ansC++
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cmath>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
class Solution {
public:
int diagonalSum(vector<vector<int>>& mat) {
int ans = 0;
int n = mat.size();
for (int i = 0; i < n; ++i) {
int j = n - i - 1;
ans += mat[i][i] + (i == j ? 0 : mat[i][j]);
}
return ans;
}
};Java
import java.util.*;
class Solution {
public int diagonalSum(int[][] mat) {
int ans = 0;
int n = mat.length;
for (int i = 0; i < n; ++i) {
int j = n - i - 1;
ans += mat[i][i] + (i == j ? 0 : mat[i][j]);
}
return ans;
}
}复杂度
时间
O(n)
n 是矩阵边长。两条对角线最多 2n 个格子,n 为奇数时正中心重合、不同格子数是 2n 减 1,不管哪种都跟 n 成正比,按行走一遍每行最多看两个元素,根本不用扫整个 n 乘 n 的矩阵
空间
O(1)
从头到尾只用一个累加变量记答案,再加几个下标变量,不随矩阵规模增长,峰值占用是常数
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 矩阵对角线元素的和 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
怎么快速判断一个格子在不在副对角线上?+
看它的行号加列号。行号 i 加列号 j 正好等于 n 减 1,它就在副对角线上。比如 3 乘 3 的矩阵里,(0,2)、(1,1)、(2,0) 这三格的行列号之和都是 2、也就是 n 减 1,所以都在副对角线上。主对角线的判定更简单,行号等于列号 i 等于 j 即可。
为什么只有 n 是奇数时才需要去重?+
正中心要同时满足 i 等于 j 和 i 加 j 等于 n 减 1。把第一条代入第二条,得到 i 加 i 等于 n 减 1,也就是 i 等于 n 减 1 再除以 2。只有当 n 是奇数时,n 减 1 是偶数,除以 2 才落成一个合法的整数下标,这时两条对角线才真有一个公共格;n 是偶数时算出来带小数、落不到具体格子上,两条线没有交点,自然不用去重。
能不能不分两趟、用一个循环就求完?+
能,这正是参考代码的写法。按行从上往下走,对每一行 i,先加上主对角线元素、即这一行第 i 列的值,再令 j 等于 n 减 1 减 i,若 j 不等于 i 就再加上这一行第 j 列的值;当 j 等于 i 时说明这一格是正中心、主对角线已经加过,就跳过。一趟循环既加了两条对角线,又顺手完成了去重,不用先加完一条再回头补另一条。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 矩阵对角线元素的和 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。