73矩阵置0
- 1.最简单的方法就是另外开一个数组,当前数组遇到0的时候就在新开的数组上对应的行列全部置0,这样空间复杂度要O(MN)
- 2.开一个m的数组,标记对应的行有没有出现过0,开一个n的数组,标记对应的列有没有出现过0,这样的空间复杂度是O(M+N)
- 3.在上面的基础上,将第一行和第一列作为m和n的数组,标记对应行和列有没有出现0,有出现过就标记为0,但是这样原本的第一行和列的如果在该位置刚好有0,就需要将第一行和第一列也置为0,于是用两个标记来标注原本的第一行和第一列是否有出现0,这样的空间复杂度是O(1)
- 4.再在上面的基础上,只使用一个标记变量记录第一列是否原本存在 0。这样,第一列的第一个元素即可以标记第一行是否出现 0。为了防止每一列的第一个元素被提前更新,我们需要从最后一行开始,倒序地处理矩阵元素。
空间复杂度是O(1)
第三种:
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int flag_row = 0;
int flag_col = 0;
for(int i = 0 ; i < m; i++){
if(matrix[i][0] == 0){
flag_col = 1;//标记第一列是否原本有0
break;
}
}
for(int i = 0 ; i < n; i++){
if(matrix[0][i] == 0){
flag_row = 1;//标记第一行是否原本有0
break;
}
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
if(matrix[i][j] == 0){
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
if(!matrix[i][0] || !matrix[0][j]){
matrix[i][j] = 0;
}
}
}
if(flag_col){
for(int i = 0 ; i < m; i++) matrix[i][0] = 0;
}
if(flag_row){
for(int i = 0 ; i < n; i++) matrix[0][i] = 0;
}
}
};
第四种:
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int flag_col = 0;
for (int i = 0; i < m; i++) {
if (!matrix[i][0]) {
flag_col = 1;
}
for (int j = 1; j < n; j++) {
if (!matrix[i][j]) {
matrix[i][0] = matrix[0][j] = 0;
}
}
}
for (int i = m - 1; i >= 0; i--) {
for (int j = 1; j < n; j++) {
if (!matrix[i][0] || !matrix[0][j]) {
matrix[i][j] = 0;
}
}
if (flag_col) {
matrix[i][0] = 0;
}
}
}
};
289生命游戏
这题还是和之前的一样,如果考虑复制一个数组的话,就特别容易实现,但是需要O(MN)的空间复杂度,而本题是要求原地计算的。
还是想到要用标记的方法,怎么标记呢?这个和上一题不一样,上一题对数组进行修改是一整行或者一整列的来,因此用一个标记变量就能记录一整行或者一整列的状态,但是这个是针对每个元素来说都有周围八个(边界的也算八个,我们假设是无边界的,没有在数组之内的都算作是0),因此很难说用常数个标记变量来记录每个元素的状态。
难点在于怎么标记过后还能知道原来是0还是1,而不影响后面对1个数的判断。这种时候就想能不能用当前元素进行标记,因为本来的数组值只有0和1两种,而我们需要改变的也只不过是0变为1,或者1变为0两种状态,我们用2表示0变为1,用-1表示1变为0。
- 判断周围1的个数的时候除了原来就是1,再多加一种原来是1,现在变为0,也就是-1
- 遍历一遍标记结束之后,再遍历一遍,将对应的2改为1,-1改为0即可
- 时间复杂度O(MN),这是无法避免的,空间复杂度O(1)
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
//-1表示原来是活的后来死了,2表示原来死的后来活了
int nei[3] = {-1, 0, 1};
int m = board.size();
int n = board[0].size();
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
int nei_count = 0;//统计每个位置的周围八个有多少个1
for(int r = 0; r < 3; r++){
for(int c = 0; c < 3; c++){
if(nei[r] || nei[c]){ //遍历相邻的八个,除去本身的情况
int row = i + nei[r];
int col = j + nei[c];
if(row < m && row >= 0 && col < n && col >= 0 && abs(board[row][col]) == 1){ //活的有1和原来活的-1
nei_count ++;
}
}
}
}
if(board[i][j] == 1 && (nei_count < 2 || nei_count > 3)) board[i][j] = -1;
if(board[i][j] == 0 && nei_count == 3 ) board[i][j] = 2;
}
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(board[i][j] == 2 ) board[i][j] = 1;
if(board[i][j] == -1) board[i][j] = 0;
}
}
}
};