leetcode 790. Domino and Tromino Tiling

该博客讨论了LeetCode 790题,涉及使用2x1的多米诺骨牌和L型Tromino来铺满2xN的棋盘的不同方法。博主提供了两种解决方案:动态规划和矩阵快速幂。动态规划方法通过递推公式`dp[n] = dp[n-1] + dp[n-2] + 2 * Σ dpi`计算,而矩阵乘法方法利用线性代数在O(logN)时间内完成计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

leetcode 790. Domino and Tromino Tiling

题目描述

We have two types of tiles: a 2x1 domino shape, and an “L” tromino shape. These shapes may be rotated.
——————————————————
XX <- domino

XX <- “L” tromino
X
——————————————————

Given N, how many ways are there to tile a 2 x N board? Return your answer modulo 10^9 + 7.
(In a tiling, every square must be covered by a tile. Two tilings are different if and only if there are two 4-directionally adjacent cells on the board such that exactly one of the tilings has both squares occupied by a tile.)

Note:

  • N will be in range [1, 1000].

Difficulty: medium
790. Domino and Tromino Tiling


中文描述
你拥有两种形状的多米诺骨牌,一种是XX这样 2x1 形状的,还有一种是L型的。问铺满 2xN 的空间,一共能有多少种不同的方法。结果对10^9 + 7取余数。


输入格式
输入一个值N,表示长度。


Examples:

  1. Input: 3
    Output: 5
    解释:
    总共有5中方法组成 2X3 的矩形
    XYZ XXZ XYY XXY XYY
    XYZ YYZ XZZ XYY XXY

解答思路

  • 解法一:dp解法
    n从1到4的情况

    1.可以从图里看出, n=1n=2 n = 1 和 n = 2 的时候为基础情况,在 n=3 n = 3 开始就能发现一定规律。 n=3 n = 3 的第一行,是由 n=2 n = 2 的情况加上一个2X1的多米诺牌放在末尾组成的。 n=3 n = 3 的第二行的前半部分是由 n=1 n = 1 的情况加上两个2X1的多米诺牌横放,放在末尾组成的。 n=3 n = 3 的第二行的后半部分则是不由 n=12 n = 1 , 2 的情况组成的。同理 n=4 n = 4 的第一行,是由 n=3 n = 3 的情况加上一个2X1的多米诺牌放在末尾组成的。 n=4 n = 4 的第二行是由 n=2 n = 2 的情况加上两个2X1的多米诺牌横放,放在末尾组成的。 n=4 n = 4 的第三行的前半部分则是由 n=1 n = 1 加上两个L型的多米诺牌放在末尾组成的。 n=4 n = 4 的第三行的后半部分则是不由 n=123 n = 1 , 2 , 3 的情况组成的。

    2.从上我们的大概可以总结规律,每个 n n 都是由之前n1的情况配合组成的。 dpn d p n 表示第 2×n 2 × n 个的组合个数。
    其公式为 dpn=dpn1+dpn2+2×i=0n3dpi,dp0=1 d p n = d p n − 1 + d p n − 2 + 2 × ∑ i = 0 n − 3 d p i , 其 中 d p 0 = 1 dpn1 d p n − 1 表示以一个2X1的多米诺牌放在末尾组成的, dpn2 d p n − 2 表示以两个2X1的多米诺牌横放,放在末尾组成的,剩下的则是由带有L型为末尾的。结尾形状具体可以看下图:
    结尾情况
    n3 n − 3 以后都是有2种,所以需要乘2.

    3.上述式子可以简化,用 dpndpn1=dpn1+dpn2+2×i=0n3dpi(dpn2+dpn3+2×i=0n4dpi) d p n − d p n − 1 = d p n − 1 + d p n − 2 + 2 × ∑ i = 0 n − 3 d p i − ( d p n − 2 + d p n − 3 + 2 × ∑ i = 0 n − 4 d p i ) ,化简得到 dpn=2dpn1dpn3 d p n = 2 d p n − 1 − d p n − 3 。这就是递推方程。

    4.复杂度估计 O(n) O ( n )

  • 解法二:矩阵乘法

    1. dpn=dpn1+dpn2+2×i=0n3dpi,dp0=1 d p n = d p n − 1 + d p n − 2 + 2 × ∑ i = 0 n − 3 d p i , 其 中 d p 0 = 1 ,写成矩阵形式为

    [a1b1c1]×dpn1dpn2i=0n3dpi=[a2b2c2]×dpn2dpn3i=0n4dpi=...=[an2bn2cn2]×dp2dp1dp0=2an2+bn2+cn2 [ a 1 b 1 c 1 ] × [ d p n − 1 d p n − 2 ∑ i = 0 n − 3 d p i ] = [ a 2 b 2 c 2 ] × [ d p n − 2 d p n − 3 ∑ i = 0 n − 4 d p i ] = . . . = [ a n − 2 b n − 2 c n − 2 ] × [ d p 2 d p 1 d p 0 ] = 2 a n − 2 + b n − 2 + c n − 2

    其中 a1=1,b1=1,c1=2 a 1 = 1 , b 1 = 1 , c 1 = 2
    我们取 [ak1bk1ck1]×dpnk+1dpnki=0nk1dpi [ a k − 1 b k − 1 c k − 1 ] × [ d p n − k + 1 d p n − k ∑ i = 0 n − k − 1 d p i ]
    由于 ak1×dpnk+1=ak1×(dpnk+dpnk1+2i=0nk2dpi) a k − 1 × d p n − k + 1 = a k − 1 × ( d p n − k + d p n − k − 1 + 2 ∑ i = 0 n − k − 2 d p i )
    所以上面矩阵乘法结果为 ak1×(dpnk+dpnk1+2i=0nk2dpi)+bk1×dpnk+ck1×i=0nk1dpi a k − 1 × ( d p n − k + d p n − k − 1 + 2 ∑ i = 0 n − k − 2 d p i ) + b k − 1 × d p n − k + c k − 1 × ∑ i = 0 n − k − 1 d p i
    =(ak1+bk1)dpnk+(ak1+ck1)dpnk1+(2ak1+ck1)i=0nk2dpi = ( a k − 1 + b k − 1 ) d p n − k + ( a k − 1 + c k − 1 ) d p n − k − 1 + ( 2 a k − 1 + c k − 1 ) ∑ i = 0 n − k − 2 d p i
    =[akbkck]×dpnkdpnk1i=0nk2dpi = [ a k b k c k ] × [ d p n − k d p n − k − 1 ∑ i = 0 n − k − 2 d p i ]
    可以得到:
    ak=ak1+bk1bk=ak1+ck1ck=2ak1+ck1 a k = a k − 1 + b k − 1 b k = a k − 1 + c k − 1 c k = 2 a k − 1 + c k − 1
    进一步:
    ak=ak2+bk2+ak2+ck2=2ak2+bk2+ck2bk=3ak2+bk2+ck2ck=4ak2+bk2+ck2 a k = a k − 2 + b k − 2 + a k − 2 + c k − 2 = 2 a k − 2 + b k − 2 + c k − 2 b k = 3 a k − 2 + b k − 2 + c k − 2 c k = 4 a k − 2 + b k − 2 + c k − 2
    转化为矩阵形式为:
    [an2bn2cn2]×211=[an4bn4cn4]×211311421×211=[an2kbn2kcn2k]×211311421k1×211 [ a n − 2 b n − 2 c n − 2 ] × [ 2 1 1 ] = [ a n − 4 b n − 4 c n − 4 ] × [ 2 3 4 1 1 2 1 1 1 ] × [ 2 1 1 ] = [ a n − 2 k b n − 2 k c n − 2 k ] × [ 2 3 4 1 1 2 1 1 1 ] k − 1 × [ 2 1 1 ]
    如果 n n 为偶数,[an2kbn2kcn2k]最小从下标2开始
    [a2b2c2]=[a1+b1a1+c12a1+c1]=[234] [ a 2 b 2 c 2 ] = [ a 1 + b 1 a 1 + c 1 2 a 1 + c 1 ] = [ 2 3 4 ]
    如果 n n 为奇数[an2kbn2kcn2k]最小从下标1开始
    [a1b1c1]=[112] [ a 1 b 1 c 1 ] = [ 1 1 2 ]
    这样我们可以用大数乘法的方法,只用 O(logn) O ( l o g n ) 的时间完成矩阵乘法

    3.复杂度估计 O(logn) O ( l o g n ) O(logN) time O(1) space linear algebraic algorithm (in python)


代码

解法一,

class Solution(object):
    def numTilings(self, N):
        """
        :type N: int
        :rtype: int
        35MS
        """
        if N == 1:
            return 1
        if N == 2:
            return 2
        dp = [1 for _ in range(N + 1)]
        dp[2] = 2
        for i in range(3, N + 1):
            dp[i] = (2 * dp[i - 1] + dp[i - 3]) % int(1e9 + 7)
        return dp[-1]

解法二,使用numpy库,直接使用矩阵乘法:

class Solution(object):
    def numTilings(self, N):
        """
        :type N: int
        :rtype: int
        95MS
        """
        import numpy as np
        if N == 1:
            return 1
        if N == 2:
            return 2
        if N % 2 == 1:
            k = (N - 2) // 2
            # a1,b1,c1
            start = np.array([1, 1, 2], dtype=np.int64)
        else:
            k = (N - 4) // 2
            # a2,b2,c2
            start = np.array([2, 3, 4], dtype=np.int64)
        A = np.array([[2, 3, 4], [1, 1, 2], [1, 1, 1]], dtype=np.int64)
        while k > 0:
            # 相当于转化为2进制
            if k % 2 == 1:
                start = np.dot(start, A) % 1000000007
            k //= 2
            A = A.dot(A) % 1000000007

        return int(np.dot(start, np.array([[2],[1],[1]], dtype=np.int64)) % 1000000007)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值