【LeetCode学习计划】《数据结构入门-C++》第5天 数组

LeetCode【学习计划】:【数据结构】



36. 有效的数独

LeetCode: 36. 有效的数独

中 等 \color{#FFB800}{中等}

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
1.数字 1-9 在每一行只能出现一次。
2.数字 1-9 在每一列只能出现一次。
3.数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 空白格用 '.' 表示。

示例 1:
在这里插入图片描述

输入:board = 
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
输出:true

示例 2:

输入:board = 
[["8","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
输出:false
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

提示:

  • board.length == 9
  • board[i].length == 9
  • board[i][j] 是一位数字(1-9)或者 '.'

哈希表

可以为每一行、每一列和每一个3x3的宫设置一个哈希表,一共是9+9+9=27个哈希表。遍历九宫格的过程中,记录一个元素时需要在它所对应的行、列和宫的哈希表中记录,一个元素一共记录3次。

由于我们一般是按照一行一行地去遍历,所以可以把行哈希表缩减为一个,也就是每一行遍历完后重置哈希表。这样哈希表就变为了1+9+9=19个。

#include <vector>
using namespace std;
class Solution
{
public:
    bool isValidSudoku(vector<vector<char>> &board)
    {
        int columns[9][9] = {};
        int boxes[3][3][9] = {};

        for (int i = 0; i < 9; i++)
        {
            int row[9] = {};
            for (int j = 0; j < 9; j++)
            {
                if (board[i][j] != '.')
                {
                    const int index = board[i][j] - '0' - 1;
                    if (row[index] == 1 || columns[j][index] == 1 || boxes[i / 3][j / 3][index] == 1)
                        return false;

                    row[index]++;
                    columns[j][index]++;
                    boxes[i / 3][j / 3][index]++;
                }
            }
        }
        return true;
    }
};

复杂度分析

  • 时间复杂度: O ( 1 ) O(1) O(1)。九宫格一共有81格,一共遍历81次,因此遍历的次数是确定的。

  • 空间复杂度: O ( 1 ) O(1) O(1)。由于数独的大小固定,所以哈希表的大小也是固定的。

参考结果

Accepted
507/507 cases passed (12 ms)
Your runtime beats 95.57 % of cpp submissions
Your memory usage beats 73.07 % of cpp submissions (17.5 MB)


73. 矩阵置零

LeetCode: 73. 矩阵置零

中 等 \color{#FFB800}{中等}

给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

进阶:

  • 一个直观的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
  • 一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
  • 你能想出一个仅使用常量空间的解决方案吗?

示例 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.length
  • n == matrix[0].length
  • 1 <= m, n <= 200
  • -231 <= matrix[i][j] <= 231 - 1

方法1:使用标记数组

假设matrix的行数为m,列数为n,我们可以设置一个m长的rown长的col作为标记数组,用于标记每一行、每一列是否有零出现。我们先完整遍历一次matrix,记录哪里有零;最后根据rowcol数组将matrix对应的行和列全部置零。

#include <vector>
using namespace std;
class Solution
{
public:
    void setZeroes(vector<vector<int>> &matrix)
    {
        const int m = matrix.size(), n = matrix[0].size();
        bool *row = new bool[m]{}, *col = new bool[n]{};

        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (matrix[i][j] == 0)
                {
                    row[i] = true;
                    col[j] = true;
                }
            }
        }
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (row[i] || col[j])
                {
                    matrix[i][j] = 0;
                }
            }
        }
    }
};

复杂度分析

  • 时间复杂度: O ( m n ) O(mn) O(mn)。最多完整遍历矩阵2次, O ( 2 m n ) = O ( m n ) O(2mn)=O(mn) O(2mn)=O(mn)

  • 空间复杂度: O ( m + n ) O(m+n) O(m+n)。主要为两个标记数组的开销。

参考结果

Accepted
164/164 cases passed (12 ms)
Your runtime beats 79.12 % of cpp submissions
Your memory usage beats 69.92 % of cpp submissions (12.8 MB)

方法2:使用2个标记变量

我们可以用矩阵的第一行和第一列来代替方法1中的标记数组,如果某一行某一列存在0,那么就将原矩阵的第一行和第一列对应的位置置零,这样就能剩下两个额外的数组开销了,并且空间复杂度降为了 O ( 1 ) O(1) O(1)

不过这样一来,矩阵的第一行第一列原来有没有0就不清楚了,如果第一行或第一列本来就有0的话,最后要把它们单独置零,因此需要两个标记变量分别表示第一行和第一列原先是否含0

方法2的步骤如下:

  1. 标记第一行和第一列中是否含有零。
  2. 遍历整个数组,发现0时,更新第一行和第一列对应的位置为零。
  3. 通过第一行和第一列去更新整个数组
  4. 若第一行或第一列本身含有零,那么单独为第一行或第一列置零。
#include <vector>
using namespace std;
class Solution
{
public:
    void setZeroes(vector<vector<int>> &matrix)
    {
        int m = matrix.size(), n = matrix[0].size();
        bool row0Has0 = false, col0Has0 = false;
        // 设第0行和第0列为标记量
        for (int j = 0; j < n; j++)
        {
            if (matrix[0][j] == 0)
            {
                row0Has0 = true;
                break;
            }
        }
        for (int i = 0; i < m; i++)
        {
            if (matrix[i][0] == 0)
            {
                col0Has0 = true;
                break;
            }
        }

        // 更新标记量
        for (int i = 1; i < m; i++)
        {
            for (int j = 1; j < n; j++)
            {
                if (matrix[i][j] == 0)
                {
                    matrix[0][j] = matrix[i][0] = 0;
                }
            }
        }

        // 使用标记量去更新矩阵
        for (int j = 1; j < n; j++)
        {
            if (matrix[0][j] == 0)
            {
                for (int i = 1; i < m; i++)
                {
                    matrix[i][j] = 0;
                }
            }
        }
        for (int i = 1; i < m; i++)
        {
            if (matrix[i][0] == 0)
            {
                for (int j = 1; j < n; j++)
                {
                    matrix[i][j] = 0;
                }
            }
        }

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

复杂度分析

  • 时间复杂度: O ( m n ) O(mn) O(mn)

  • 空间复杂度: O ( 1 ) O(1) O(1)。我们只需要常量空间来存储若干变量。

参考结果

Accepted
164/164 cases passed (16 ms)
Your runtime beats 44.42 % of cpp submissions
Your memory usage beats 69.88 % of cpp submissions (12.8 MB)
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亡心灵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值