难度标识:
⭐:简单,⭐⭐:中等,⭐⭐⭐:困难。
tips:这里的难度不是根据LeetCode难度定义的,而是根据我解题之后体验到题目的复杂度定义的。
1.矩阵置零 ⭐
思路
思路1
这题题目要求使用原地算法,那我们就需要使用矩阵中的内容去记录哪些位置是需要置0的。首先我们使用第一行和第一列来记录需要置0的位置。
- 利用原矩阵的第一行和第一列来记录该行该列是否需要置0
-
首先,我们需要两个标记变量,一个记录第一行是否需要置0,一个记录第一列是否需要置0。
-
然后,从第二行第二列开始,遍历整个矩阵,用矩阵的第一行和第一列来记录对应行或列是否需要置0。
- 遍历完矩阵后,再次从第二行第二列开始,根据第一行和第一列来进行置0操作
- 如果某个元素对应的第一行和第一列的元素有一个是0,那么这个元素就需要置0。
- 最后,根据我们开始时设置的两个标记变量来确定第一行和第一列是否需要置0
代码见下面思路1代码。
思路2
根据上面的思路,我们可以优化一下,只使用第一列来记录是否需要置0,详细思路可以看这个视频,讲的很清楚。代码见下面思路2代码。推荐使用思路2,理解了也很简单,代码量也少。
代码
思路1代码
var setZeroes = function (matrix) {
const m = matrix.length;
const n = matrix[0].length;
let rowFlag = false;
let colFlag = false;
// Step 1: 判断第一行和第一列是否需要被设置为0
for (let i = 0; i < m; i++) {
if (matrix[i][0] === 0) {
colFlag = true;
break;
}
}
for (let j = 0; j < n; j++) {
if (matrix[0][j] === 0) {
rowFlag = true;
break;
}
}
// Step 2: 使用第一行和第一列记录其他行和列是否需要被设置为0
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
if (matrix[i][j] === 0) {
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
// Step 3: 使用第一行和第一列的记录来将其他行和列设置为0
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
if (matrix[i][0] === 0 || matrix[0][j] === 0) {
matrix[i][j] = 0;
}
}
}
// Step 4: 根据之前的记录来决定第一行和第一列是否需要被设置为0
if (colFlag) {
for (let i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
if (rowFlag) {
for (let j = 0; j < n; j++) {
matrix[0][j] = 0;
}
}
};
思路2代码
var setZeroes = function (matrix) {
const m = matrix.length, n = matrix[0].length;
let flagCol0 = false
for (let i = 0; i < m; i++) {
if (matrix[i][0] === 0) {
flagCol0 = true
}
for (let j = 1; j < n; j++) {
if (matrix[i][j] === 0) {
matrix[i][0] = matrix[0][j] = 0
}
}
}
for (let i = m - 1; i >= 0; i--) {
for (let j = 1; j < n; j++) {
if (matrix[i][0] === 0 || matrix[0][j] === 0) {
matrix[i][j] = 0
}
}
if (flagCol0) {
matrix[i][0] = 0
}
}
return matrix
};
2.螺旋矩阵 ⭐
思路
这题的思路是找2个点,一个左上角那个点,另一个是右下角这个点,然后通过这两个点去进行从左到右,从上到下,从右到左,从下到上的依次遍历即可,详细讲解可以看这个视频,讲的非常清楚。
代码
var spiralOrder = function (matrix) {
const m = matrix.length, n = matrix[0].length
let top = 0, left = 0, bottom = m - 1, right = n - 1
const res = []
while (top <= bottom && left <= right) {
// 1.从左向右
for (let i = left; i <= right; i++) {
res.push(matrix[top][i])
}
// 2.从上往下
for (let i = top + 1; i <= bottom; i++) {
res.push(matrix[i][right])
}
if (top < bottom && left < right) {
// 3.从右往左
for (let i = right - 1; i > left; i--) {
res.push(matrix[bottom][i])
}
// 4.从下往上
for (let i = bottom; i > top; i--) {
res.push(matrix[i][left])
}
}
[top, left, bottom, right] = [top + 1, left + 1, bottom - 1, right - 1]
}
return res
};
3.旋转图像 ⭐
思路
这个题就很简单,通过观察发现我们可以将矩阵的行列互换,然后每一行进行反转,就可以得到我们最终需要的结果了。
-
- 首先进行主对角线(左上到右下)的翻转。这样原来的第一行就成了新的第一列,原来的第二行就成了新的第二列,依此类推。
-
- 接着对每一行进行水平翻转。这样原来的第一列就变到了最后一列,原来的第二列就变到了倒数第二列,依此类推。
代码
var rotate = function (matrix) {
const n = matrix.length
for (let i = 0; i < n; i++) {
for (let j = i; j < n; j++) {
[matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]]
}
matrix[i].reverse()
}
return matrix
};
4.搜索二维矩阵 II ⭐
思路
这题我们可以从右上角的那个值开始找起,右上角值那一行左边的值都是比它小的,右上角值那一列下面的值都是比它大的,然后我们拿这个值去和目标值比,目标值比这个值小的话那就往左走,目标值比这个值大的话那就往下走,循环这个过程即可。详细解析也可以看这个视频。
代码
var searchMatrix = function (matrix, target) {
let top = 0, right = matrix[0].length - 1
while (top < matrix.length && right >= 0) {
if (matrix[top][right] === target) {
return true
} else if (matrix[top][right] < target) {
top++
} else {
right--
}
}
return false
};
总结
整体而言,矩阵的题目只要想清楚了,解起来都很简单,不要想着是矩阵,二维数组就觉得很难,其实矩阵的题目降维到一维这些题目官方定义肯定都是简单题,因为思路很简单。