【LeetCode】动态规划—790. 多米诺和托米诺平铺(附完整Python/C++代码)

题目描述

在这里插入图片描述

前言

本文将详细讨论LeetCode上的"多米诺和三米诺平铺"问题。这是一个经典的动态规划问题,要求我们计算用多米诺骨牌和三米诺骨牌填充2x n网格的方法数。我们将从问题定义开始,逐步深入理解问题本质,提出解决方案,并给出Python和C++的具体实现。

基本思路

1. 定义

给定一个整数n,我们需要计算用1x 2的多米诺骨牌和L形的三米诺骨牌填充2 x n网格的不同方法数。结果需要对10^9 + 7取模。

2. 理解问题和递推关系

这个问题的关键在于理解如何使用动态规划来解决。我们需要找出填充方式之间的递推关系,并利用这种关系来构建解决方案。

3. 解决方法

我们可以定义dp[i]为填充2 x i网格的方法数。关键是要考虑到所有可能的填充方式:

  1. 使用一个竖直的多米诺骨牌填充最后一列:dp[i-1]
  2. 使用两个水平的多米诺骨牌填充最后两列:dp[i-2]
  3. 使用一个三米诺骨牌填充最后两列的一部分,这有两种方式

因此,我们可以得到递推公式:
dp[i] = dp[i-1] + dp[i-2] + 2 * (dp[i-3] + ... + dp[0])

4. 进一步优化

我们可以通过数学推导简化上述公式。令S[i] = dp[i-3] + ... + dp[0],那么:
S[i] = S[i-1] + dp[i-3]
dp[i] = dp[i-1] + dp[i-2] + 2 * S[i]

这样,我们可以在O(1)时间内计算每个状态,将时间复杂度优化到O(n)。

5. 小总结

通过分析填充方式并建立递推关系,我们成功地将问题转化为了一个动态规划问题。通过数学推导,我们进一步优化了算法的时间复杂度。

以上就是多米诺和托米诺平铺问题的基本思路。


代码实现

Python代码

class Solution:
    def numTilings(self, n: int) -> int:
        MOD = 10**9 + 7
        if n <= 2:
            return n
        #初始化dp数组
        dp = [0] * (n + 1)
        dp[0], dp[1], dp[2] = 1, 1, 2
        
        # 初始化S
        S = 1
        
        # 动态规划过程
        for i in range(3, n + 1):
            dp[i] = (dp[i-1] + dp[i-2] + 2 * S) % MOD
            S = (S + dp[i-2]) % MOD
        
        return dp[n]

在这里插入图片描述

Python代码解释总结

这段Python代码实现了优化后的动态规划算法。我们使用dp数组存储每个状态的解,使用S变量来存储优化后的累加和。通过一次遍历,我们可以在O(n)的时间复杂度内求解问题。代码中的取模操作确保了结果在给定范围内。

C++代码

class Solution {
public:
    int numTilings(int n) {
        const int MOD = 1e9 + 7;
        if (n <= 2) return n;
        
        // 初始化dp数组
        vector<long long> dp(n + 1, 0);
        dp[0] = 1; dp[1] = 1; dp[2] = 2;
        
        // 初始化S
        long long S = 1;
        
        // 动态规划过程
        for (int i = 3; i <= n; ++i) {
            dp[i] = (dp[i-1] + dp[i-2] + 2 * S) % MOD;
            S = (S + dp[i-2]) % MOD;
        }
        
        return dp[n];
    }
};

在这里插入图片描述

C++代码解释总结

C++代码的实现逻辑与Python版本相同,都是基于优化后的动态规划算法。使用vector<long long>来存储dp数组,以避免整数溢出。同样通过一次遍历完成所有状态的计算,时间复杂度为O(n)。

总结

通过本文的分析和实现,我们深入理解了"多米诺和三米诺平铺"问题的本质,并学习了如何使用动态规划来解决此类组合问题。我们不仅给出了基本的解决方案,还通过数学推导对算法进行了优化,最终得到了时间复杂度为O(n)的高效解法。Python和C++的实现展示了如何将理论转化为实际代码,这对于理解和掌握动态规划技巧很有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ALSKai

今天又能喝柠檬茶啦

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

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

打赏作者

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

抵扣说明:

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

余额充值