脑筋急转弯
补充证明 灵茶山艾府找不到规律?请看图!(Python/Java/C++/Go)
一定要看链接里的图!本题为看图的形象证明!!
定义:
d
p
[
n
]
dp[n]
dp[n] 是
2
×
n
2\times n
2×n 矩形的 所有姿态 组成的状态。
一般规律:对于
i
+
j
=
n
i+j=n
i+j=n ,
d
p
[
n
]
dp[n]
dp[n] 包含
d
p
[
j
]
dp[j]
dp[j] 拼接 在
d
p
[
i
]
dp[i]
dp[i] 后组成的任何姿态。
如:
n
=
4
n=4
n=4 ,
d
p
[
4
]
dp[4]
dp[4] 包含
d
p
[
1
]
dp[1]
dp[1] 拼接在
d
p
[
3
]
dp[3]
dp[3] 后组成的任何姿态。
在链接中,找到新规律。从
d
p
[
3
]
dp[3]
dp[3] 开始,每一个新状态都会多出两种 特有姿态 。
特有姿态
s
p
[
i
]
sp[i]
sp[i] 定义:不由之前状态拼接的全新姿态。
特有姿态如下:
观察,记录
d
p
[
i
]
dp[i]
dp[i] 对应的特有姿态
s
p
[
i
]
sp[i]
sp[i],有
①
s
p
[
1
]
=
s
p
[
2
]
=
1
sp[1] = sp[2] = 1
sp[1]=sp[2]=1
②
s
p
[
3
]
=
s
p
[
4
]
=
⋯
=
s
p
[
n
]
=
2
sp[3] = sp[4] = \dots =sp[n]=2
sp[3]=sp[4]=⋯=sp[n]=2
对于 i + j = n i+j=n i+j=n ,遍历 i = n − 1 , n − 2 , n − 3 , … , 2 , 1 i = n-1,n-2,n-3,\dots ,2,1 i=n−1,n−2,n−3,…,2,1 ; j = 1 , 2 , 3 , … , n − 2 , n − 1 j = 1,2,3,\dots ,n-2,n-1 j=1,2,3,…,n−2,n−1 ,将 j j j 的特有姿态 s p [ j ] sp[j] sp[j] ,拼接在 i i i 的所有姿态 d p [ i ] dp[i] dp[i] 后,就可以 不重不漏 的组成 n n n 的所有姿态 d p [ n ] dp[n] dp[n] 。
数学证明,可以略过,看结论
(可以不看)得到递推式 ③
d
p
[
n
]
=
d
p
[
n
−
1
]
×
s
p
[
1
]
+
d
p
[
n
−
2
]
×
s
p
[
2
]
+
d
p
[
n
−
3
]
×
s
p
[
3
]
+
⋯
+
d
p
[
1
]
×
s
p
[
n
−
1
]
dp[n] = dp[n-1]\times sp[1] + dp[n-2]\times sp[2] +dp[n-3]\times sp[3] +\dots+dp[1]\times sp[n-1]
dp[n]=dp[n−1]×sp[1]+dp[n−2]×sp[2]+dp[n−3]×sp[3]+⋯+dp[1]×sp[n−1]。
①②代入③,得
d
p
[
n
]
=
d
p
[
n
−
1
]
+
d
p
[
n
−
2
]
+
2
×
d
p
[
n
−
3
]
+
2
×
d
p
[
n
−
4
]
+
⋯
+
2
×
d
p
[
1
]
dp[n] = dp[n-1] + dp[n-2] + 2\times dp[n-3] + 2\times dp[n-4] +\dots +2\times dp[1]
dp[n]=dp[n−1]+dp[n−2]+2×dp[n−3]+2×dp[n−4]+⋯+2×dp[1]
整理,得 ④
d
p
[
n
]
=
d
p
[
n
−
1
]
+
d
p
[
n
−
2
]
+
2
×
(
d
p
[
n
−
3
]
+
d
p
[
n
−
4
]
+
⋯
+
d
p
[
1
]
)
dp[n] = dp[n-1] + dp[n-2] + 2\times (dp[n-3] + dp[n-4] +\dots + dp[1])
dp[n]=dp[n−1]+dp[n−2]+2×(dp[n−3]+dp[n−4]+⋯+dp[1])
又⑤
d
p
[
n
−
1
]
=
d
p
[
n
−
2
]
+
d
p
[
n
−
3
]
+
2
×
(
d
p
[
n
−
4
]
+
d
p
[
n
−
5
]
+
⋯
+
d
p
[
1
]
)
dp[n-1] = dp[n-2] + dp[n-3] + 2\times (dp[n-4] + dp[n-5] +\dots + dp[1])
dp[n−1]=dp[n−2]+dp[n−3]+2×(dp[n−4]+dp[n−5]+⋯+dp[1])
结论
④-⑤,得
d
p
[
n
]
−
d
p
[
n
−
1
]
=
d
p
[
n
−
1
]
+
d
p
[
n
−
3
]
dp[n] - dp[n-1] = dp[n-1]+dp[n-3]
dp[n]−dp[n−1]=dp[n−1]+dp[n−3]
结论:
d
p
[
n
]
=
2
×
d
p
[
n
−
1
]
+
d
p
[
n
−
3
]
dp[n] = 2\times dp[n-1] + dp[n-3]
dp[n]=2×dp[n−1]+dp[n−3]
思考过程,可以不看
(可以不看) 对于 i + j = n i+j=n i+j=n ,遍历 i = n − 1 , n − 2 , n − 3 , … , 2 , 1 i = n-1,n-2,n-3,\dots ,2,1 i=n−1,n−2,n−3,…,2,1 一定有 j = 1 , 2 , 3 , … , n − 2 , n − 1 j = 1,2,3,\dots ,n-2,n-1 j=1,2,3,…,n−2,n−1 ,将 d p [ j ] dp[j] dp[j] 拼接在 d p [ i ] dp[i] dp[i] 后,组成 n n n 的所有姿态 d p [ n ] dp[n] dp[n]。差在包含重复姿态,好在包含所有姿态。对这一步优化,发现了特有姿态 s p sp sp。
class Solution {
public:
int numTilings(int n) {
long long dp[n+10];
int mod = 1e9+7;
memset(dp,0,sizeof dp);
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
for(int i = 3;i<=n;i++) dp[i] = (2*dp[i-1] + dp[i-3])%mod;
return dp[n];
}
};
时间复杂度 :
O
(
n
)
O(n)
O(n) 。
空间复杂度 :
O
(
n
)
O(n)
O(n) 。