leetcode 73 Set Matrix Zeros 矩阵置零

leetcode 73 Set Matrix Zeros
原题链接 https://leetcode.com/problems/set-matrix-zeroes/

题目描述

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
m x n的数组,如果某元素是0,则将其所在的行和列的所有元素置零。

题目中给出了要求,Did you use extra space?

  • A straight forward solution using O(mn) space is probably a bad idea.
    使用另一个m*n的数组,不好
  • A simple improvement uses O(m + n) space, but still not the best solution.
    使用大小为m+n的额外空间,还不是最优解
  • Could you devise a constant space solution?
    能否用常量级的空间来解决?

关于不好的解法

显然题目要求中指明了三中解法,其中前两种均为不好的解法。不过我们这里还是简单说一下。

使用O(m*n)空间的解法
  • 假设原始数据为X[m][n],复制一份数据到Y[m][n]
  • 然后遍历Y,根据其中的元素来对X中的元素进行置零。

空间复杂度O(m*n);对于时间复杂度,复制需要O(m*n),然后遍历Y并处理X是O(m*n*(m+n))。可见空间复杂度和时间复杂度都不好。

使用O(m+n)空间的解法
  • 使用数组X[m]来记录某一列是否需要置零,用Y[n]来记录某一行是否需要置零
  • 遍历原始数据,如果某一元素为0,则修改X和Y中相应的标记位
  • 遍历X,如果标记为真则对原始数据中的相应进行置零
  • 遍历Y,如果标记为真则对原始数据中的相应进行置零

这个算法的空间复杂度为O(m+n),时间复杂度O(m*n)。

最优解(O(m*n) + O(c))

上面中的解法二时间复杂度为O(m*n),对于这个题目来说已经没有什么可以显著改进的地方,空间上题目要求了只用常量级空间,我们可以考虑,从解法二中进行优化,既然不让用O(m+n)的空间,我们尝试用原始数据中的空间来标记好了。

算法描述
  • 按从左到右从上到下的顺序找到原始数据中第一个0元素(其实可以是任意一个0元素),假设为X[row][col],则用X中的第row行和第col列空间来作为标记空间。其中第row行用来标记某一列是否需要置零第col列用来标记某一行是否需要置零
  • 遍历原始数据,如果某一元素为X[i][j]=0,则修改X[row][j]X[i][col]
  • 根据第row行和第col列,对X中的元素进行置零

对于上述算法,只要某一行中存在至少一个0,就把第col列中对应的元素置零,只要某一列中存在至少一个0,就把第row行中对应的元素置零。

接下来代码实现就比较简单了。不过还是要注意,标记位设定好之后,按照第row行和第col列的元素的值(是否为0)来对X进行设置,这时候,应该只处理除了第row行和第col列之外的其他元素(因为我们是按这些值来处理的,如果我们把他们设为0,将会影响后面的处理),最后的时候再单独将第row行和第col列分别设为0。

空间复杂度O(c),时间复杂度O(m*n)。

代码
// 矩阵置零
// 如果一个元素为0,则把其所在行和列均置零
void setZeroes(int** matrix, int matrixRowSize, int matrixColSize) {
    // 先找到第一个为0的元素,
    // 用其所在的行和列来作为存储某一列和某一行是否需要清零的标志的空间
    int row = -1, col = -1;
    int i, j;
    for (i = 0; i < matrixRowSize; ++i) {
        for (j = 0; j < matrixColSize; ++j)
            if (!*(*(matrix + i) + j)) { // 找到0元素
                row = i; // 第row行的空间用来标志某一列是否需要清零
                col = j; // 第col列的空间用来标志某一行是否需要清零
                break;
            }
        if (row != -1) // 第一个0元素已经找到,跳出循环
            break;
    }

    // 如果row=-1,说明没有元素为0,无需置零操作
    if (row == -1) 
        return;

    // 继续循环遍历,并对需要置零和行和列进行标记
    for (i = row; i < matrixRowSize; ++i)
        for (j = 0; j < matrixColSize; ++j)
            if (!*(*(matrix + i) + j)) { // 找到0元素
                *(*(matrix + row) + j) = *(*(matrix + i) + col) = 0;
            }

    // 遍历第row行,将相应列的所有元素置零
    for (j = 0; j < matrixColSize; ++j)
        // 暂不处理第col列
        if (j != col && !*(*(matrix + row) + j)) {
            for (i = 0; i < matrixRowSize; ++i)
                *(*(matrix + i) + j) = 0;
        }
    // 遍历第col列,将相应行的所有元素置零
    for (i = 0; i < matrixRowSize; ++i)
        // 暂不处理第row行
        if (i != row && !*(*(matrix + i) + col))
            for (j = 0; j < matrixColSize; ++j)
                *(*(matrix + i) + j) = 0;

    // 将第col列的元素置零
    for (i = 0; i < matrixRowSize; ++i)
        *(*(matrix + i) + col) = 0;
    // 将第row行的元素置零
    for (j = 0; j < matrixColSize; ++j)
        *(*(matrix + row) + j) = 0;
}
测试数据
  1. 处理前 matrix = [[9, -6, -1, -2, -5,], [-1, 3, 2, -4, 0], [-3, -4, 0, 4, -5]];
    处理后 matrix = [[9, -6, 0, -2, 0],[0, 0, 0, 0, 0],[0, 0, 0, 0, 0]].
  2. 处理前 matrix = [[0, 2, 3, 4, 5], [1, 2, 3, 0, 5], [1, 2, 3, 4, 5]];
    处理后 matrix = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0],[0, 2, 3, 0, 5]].

// 个人学习记录,若有错误请指正,大神勿喷
// sfg1991@163.com
// 2015-05-05

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值