leetcode 73. 矩阵置零

88 阅读3分钟

1. 题目介绍

题目链接:leetcode.cn/problems/se…

2. 思路

本题的难点在于要使用原地修改的方式来处理矩阵,一般会想到原地打标记的方式来处理矩阵,但是处理过程中,将矩阵中的原数置处理,可能会影响接下来的遍历。

2.1 使用hash方式来打标记

这是我自己想到的一种方式,因为考虑到不能开辟一个新的空间来记录标记,那么,直接将数组中的数据改成一个特殊值那最好。

算法流程:

  1. 遍历整个数组,如果有数据为0,则将其保存的值改为计算的hash值。
  2. 再次整个数组,如果该位置的数据和hash值相等,则修改该处对应行和对应列的所有非hash值的数据为0(因为直接列和行的数据全改成0,可能会丢掉同样行/列的原来值为0的标记)
  3. 再次遍历整个数组,将所有打上标记的hash值改成0
class Solution {
public:
    // 自定义的一个hash函数,不是很好,但这里足够用
    int myHash(long long x, long long y) {
        return (100007 + x * x + y * y) % 1000000000007;
    }
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();

        // 1.第一次遍历整个矩阵,对于0值,打上标记
        for(int i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if(matrix[i][j] == 0) {
                    matrix[i][j] = myHash(i, j);
                }
            }
        }

        // 2.再次遍历矩阵,对于已有标记,将对应行/列的非标记数据置为0
        for(int i = 0; i < m; ++i) {
            for(int j =0; j < n; ++j) {
                if(matrix[i][j] == myHash(i, j)) {
                    for(int di = 0; di < m; ++di) {
                        if(matrix[di][j] != myHash(di, j)) {
                            matrix[di][j] = 0;
                        }
                    }

                    for(int dj = 0; dj < n; ++dj) {
                        if(matrix[i][dj] != myHash(i, dj)) {
                            matrix[i][dj] = 0;
                        }
                    }
                }
            }
        }

        // 3. 遍历整个矩阵,将原来打上标记的值置为0
        for(int i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if(matrix[i][j] == myHash(i, j)) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
};

2.2 利用第一行和第一列来标记

这个也是官方题解的第二种方法。
leetcode.cn/problems/se…
可以利用第一行来记录所有需要置0的列,用第一列来记录所有需要置0的行。那么需要怎么处理原来第一行/列有0的情况?
这里有个小细节需要我们发现到,一旦第一行有0,则该行整行都需要置为0,同理,第一列有0,则整列都需要置0,因此我们可以提前先记录第一行/列的0情况,最后处理。

算法流程:

  1. 记录第一行和第一列的0情况,用两个flag保存
  2. 遍历整个矩阵,如果有0,则将对应列第一行,以及对应行第一列打上标记(置为0)
  3. 根据第一行的标记,将对应列的所有数据置为0,同理,根据第一列情况将行置0
  4. 最后,按照1中记录的flag,将第一行/列整个置0
class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();

        // 记录第一行和第一列的0的情况
        int zero_row0 = false;
        int zero_col0 = false;
        for(int i = 0; i < m; ++i) {
            if(matrix[i][0] == 0) {
                zero_col0 = true;
            }
        }
        for(int j = 0; j < n; ++j) {
            if(matrix[0][j] == 0) {
                zero_row0 = true;
            }
        }

        // 遍历整个矩阵,在第一行/列打标记
        for(int i = 1; i < m; ++i) {
            for(int j = 1; j < n; ++j) {
                if(matrix[i][j] == 0) {
                    matrix[0][j] = 0;
                    matrix[i][0] = 0;
                }
            }
        }

        // 根据第一行/列的标记情况,置0
        for(int i = 1; i < m; ++i) {
            if(matrix[i][0] == 0) {
                for(int j = 1; j < n; ++j) {
                    matrix[i][j] = 0;
                }
            }
        }

        for(int j = 1; j < n; ++j) {
            if(matrix[0][j] == 0) {
                for(int i = 1; i < m; ++i) {
                    matrix[i][j] = 0;
                }
            }
        }

        // 最后处理,第一行/列的情况,整行/列置0
        if(zero_row0) {
            for(int j = 0; j < n; ++j) {
                matrix[0][j] = 0;
            }
        }

        if(zero_col0) {
            for(int i = 0; i < m; ++i) {
                matrix[i][0] = 0;
            }
        }
    }
};