Day05[26/3/5]T73.矩阵置零
给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
示例 1:
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
示例 2:
输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]
提示:
m == matrix.lengthn == matrix[0].length1 <= m, n <= 200-231 <= matrix[i][j] <= 231 - 1
进阶:
- 一个直观的解决方案是使用
O(mn)的额外空间,但这并不是一个好的解决方案。 - 一个简单的改进方案是使用
O(m + n)的额外空间,但这仍然不是最好的解决方案。 - 你能想出一个仅使用常量空间的解决方案吗?
解题思路
首先想到:创建两个 set(集合,也就是元素不能重复且排序的数组)
扫描所有的 0 元素,把每个元素的行号和列号各自记录到一个 set 里
最后,根据这两个 set 把指定行和列全部置零就可以了 。
优化:这里空间复杂度是 O(m+n)
你不用非要创建两个 set,你把这个矩阵的第 0 行和第 0 列就当作是 set 就可以了,
比如说,data[a][b] = 0,那么把 data[a][0] 和 data[0][b] 都置为 0 不就行了,
最后去检查第 0 行和第 0 列哪些元素为 0,再把相应行和列置零就可以了。
注意:
置零的时候考虑 data[0][0]==0时,你先扫描行,会导致第 0 列全 0,然后你再扫描列的时候,就会把所有行都置零,导致整个矩阵全 0。先扫描列也是同理。所以应该在开始时避开这个元素,最后单独处理这个元素。
扫描的时候也会有类似的问题,也请考虑。
(本质就是 [0][0] 位置上的 0,你不确定是代表,这一行需要置零,还是这一列需要置零,还是行列都需要置零,所以需要引入标志位来做出区分)
Code
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
class Solution
{
public:
void setZeroes(vector<vector<int>> &matrix)
{
// step.1 扫描0元素
// 为了避免[0][0]不确定是指行0还是列0还是行列均0
// 先考虑第0行第0列本身有无0,然后排除第0行和第0列进行扫描
int flag00 = 0;
if (matrix[0][0] == 0)
{
// 行列都要置零
flag00 = 2;
}
else
{
// 扫描0行
for (int j = 0; j < matrix[0].size(); j++)
{
if (matrix[0][j] == 0)
{
// 1 表示第0行需要置零
flag00 = 1;
break;
}
}
// 扫描0列
for (int i = 0; i < matrix.size(); i++)
{
if (matrix[i][0] == 0)
{
if (flag00 == 0)
{
// -1 只有列需要置零
flag00 = -1;
}
else
{
// 2 行列都需要置零
flag00 = 2;
}
break;
}
}
}
for (int i = 1; i < matrix.size(); i++)
{
for (int j = 1; j < matrix[0].size(); j++)
{
// 检查置零
if (matrix[i][j] == 0)
{
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
// step.2 置零
// 一定要考虑到matrix[0][0]==0时会导致全0
// 所以两次搜索都避开[0][0]
// 第0列扫描,先找出需要置零的行(避开[0][0])
for (int i = 1; i < matrix.size(); i++)
{
if (matrix[i][0] == 0)
{
// 不用从0列开始
for (int j = 1; j < matrix[0].size(); j++)
{
matrix[i][j] = 0;
}
}
}
// 第0行扫描,找出要置零的列(避开[0][0])
for (int j = 1; j < matrix[0].size(); j++)
{
if (matrix[0][j] == 0)
{
// 不用处理第0行
for (int i = 1; i < matrix.size(); i++)
{
matrix[i][j] = 0;
}
}
}
// 单独处理[0][0]
// 行置零
if (flag00 == 1 || flag00 == 2)
{
for (int j = 0; j < matrix[0].size(); j++)
{
matrix[0][j] = 0;
}
}
// 列置零
if (flag00 == -1 || flag00 == 2)
{
for (int i = 0; i < matrix.size(); i++)
{
matrix[i][0] = 0;
}
}
}
};
int main()
{
// vector<vector<int>> matrix = {
// {1, 1, 1},
// {1, 0, 1},
// {1, 1, 1},
// };
// 答案 [[1,0,1],[0,0,0],[1,0,1]]
vector<vector<int>> matrix = {
{0, 1, 2, 0},
{3, 4, 5, 2},
{1, 3, 1, 5},
};
// 答案 [[0,0,0,0],[0,4,5,0],[0,3,1,0]]
// vector<vector<int>> matrix = {
// {0, 1, 2, 0},
// {3, 4, 5, 2},
// {1, 3, 1, 5},
// {0, 3, 1, 5},
// {1, 3, 1, 5},
// };
// 测试
// vector<vector<int>> matrix = {
// {1, 0}};
// vector<vector<int>> matrix = {
// {1, 2, 3, 4},
// {5, 0, 7, 8},
// {0, 10, 11, 12},
// {13, 14, 15, 0},
// };
// vector<vector<int>> matrix = {
// {-4, -2147483648, 6, -7, 0},
// {-8, 6, -8, -6, 0},
// {2147483647, 2, -9, -6, -10},
// };
Solution sol;
sol.setZeroes(matrix);
cout << endl;
for (int i = 0; i < matrix.size(); i++)
{
cout << "[";
for (int j = 0; j < matrix[0].size(); j++)
{
cout << matrix[i][j] << ",";
}
cout << "]" << endl;
}
return 0;
}