题目描述
原题链接:LeetCode 3130.找出所有稳定的二进制数组II
解题思路
动态规划( o ( n 2 ) o(n^2) o(n2))
定义dp0[i][j]
为以
0
0
0结尾的有着
i
i
i个
0
0
0和
j
j
j个
1
1
1的稳定的二进制数组的数目,定义dp1[i][j]
为以
1
1
1结尾的有着
i
i
i个
0
0
0和
j
j
j个
1
1
1的稳定二进制数组的数目。
对于dp0[i][j]
的更新,我们可以先进行分类讨论:
- 当 i ≤ m i n ( l i m i t , z e r o ) , j = 0 i \le min(limit,zero),j=0 i≤min(limit,zero),j=0时,有且仅有一种方案,就是全为 1 1 1。
- 当
j
≠
0
j \ne 0
j=0时,又可以分为两种情况:
- 当
i
≤
l
i
m
i
t
i \le limit
i≤limit时,
dp0[i][j]
可以由dp0[i-1][j]
和dp1[i-1][j]
更新而来,dp0[i][j]=dp0[i-1][j]+dp1[i-1][j]
。 - 当
i
>
l
i
m
i
t
i \gt limit
i>limit时,
dp0[i-1][j]
和dp1[i-1][j]
中只有一种情况不满足添加 1 1 1个 0 0 0之后,连续 0 0 0的数量不大于 l i m i t limit limit,就是当后面 l i m i t limit limit个数都是 0 0 0的时候。这时候的方案数与dp1[i-1-limit][j]
相同。这里是dp0
而不是dp1
是因为假如是dp0
,那么也就是说这个数组有不止 l i m i t limit limit个 0 0 0,也就不满足题意。这个时候的状态转移方程为:dp0[i][j]=dp0[i-1][j]+dp1[i-1][j]-dp1[i-1-limit][j]
。
- 当
i
≤
l
i
m
i
t
i \le limit
i≤limit时,
- 当
i
=
0
i=0
i=0时,不存在满足题意的方案。
dp0[i][j]=0
。
同理也可以得到dp1[i][j]
的状态转移方程。总的状态转移方程如下:
d
p
0
[
i
]
[
j
]
=
{
1
,
i
f
i
≤
m
i
n
(
l
i
m
i
t
,
z
e
r
o
)
a
n
d
j
=
0
d
p
0
[
i
−
1
]
[
j
]
+
d
p
1
[
i
−
1
]
[
j
]
,
i
f
i
≤
l
i
m
i
t
a
n
d
j
≠
0
d
p
0
[
i
−
1
]
[
j
]
+
d
p
1
[
i
−
1
]
[
j
]
−
d
p
1
[
i
−
1
−
l
i
m
i
t
]
[
j
]
,
i
f
i
>
l
i
m
i
t
a
n
d
j
≠
0
0
,
i
f
i
=
0
dp0[i][j]= \begin{cases} 1, &if\ i\ \le min(limit,zero) \ and \ j=0 \\ dp0[i-1][j]+dp1[i-1][j], &if\ i \le limit\ and \ j \ne0 \\ dp0[i-1][j]+dp1[i-1][j]-dp1[i-1-limit][j], &if \ i \gt limit \ and \ j \ne 0 \\ 0, &if \ i=0 \end{cases}
dp0[i][j]=⎩
⎨
⎧1,dp0[i−1][j]+dp1[i−1][j],dp0[i−1][j]+dp1[i−1][j]−dp1[i−1−limit][j],0,if i ≤min(limit,zero) and j=0if i≤limit and j=0if i>limit and j=0if i=0
d
p
1
[
i
]
[
j
]
=
{
1
,
i
f
j
≤
m
i
n
(
l
i
m
i
t
,
o
n
e
)
a
n
d
i
=
0
d
p
0
[
i
]
[
j
−
1
]
+
d
p
1
[
i
]
[
j
−
1
]
,
i
f
j
≤
l
i
m
i
t
a
n
d
i
≠
0
d
p
0
[
i
]
[
j
−
1
]
+
d
p
1
[
i
]
[
j
−
1
]
−
d
p
0
[
i
]
[
j
−
1
−
l
i
m
i
t
]
,
i
f
j
>
l
i
m
i
t
a
n
d
i
≠
0
0
,
i
f
j
=
0
dp1[i][j]= \begin{cases} 1, &if\ j\ \le min(limit,one) \ and \ i=0 \\ dp0[i][j-1]+dp1[i][j-1], &if\ j \le limit\ and \ i \ne0 \\ dp0[i][j-1]+dp1[i][j-1]-dp0[i][j-1-limit], &if \ j \gt limit \ and \ i \ne 0 \\ 0, &if \ j=0 \end{cases}
dp1[i][j]=⎩
⎨
⎧1,dp0[i][j−1]+dp1[i][j−1],dp0[i][j−1]+dp1[i][j−1]−dp0[i][j−1−limit],0,if j ≤min(limit,one) and i=0if j≤limit and i=0if j>limit and i=0if j=0
###C++代码
class Solution {
public:
typedef long long LL;
int numberOfStableArrays(int zero, int one, int limit) {
LL dp1[1010][1010] = {0};
LL dp0[1010][1010] = {0};
LL mod = 1e9+7;
for(int i = 1; i <= min(limit, zero); i++) {
dp0[i][0] = 1;
}
for(int j = 1; j <= min(limit, one); j++) {
dp1[0][j] = 1;
}
for(int i = 1; i <= zero; i++) {
for(int j = 1; j <= one; j++) {
if(i <= limit) {
dp0[i][j] = dp0[i-1][j]+dp1[i-1][j];
} else {
dp0[i][j] = dp0[i-1][j]+dp1[i-1][j]-dp1[i-1-limit][j];
}
dp0[i][j] = (dp0[i][j] % mod+mod)%mod;
if(j <= limit) {
dp1[i][j] = dp0[i][j-1]+dp1[i][j-1];
} else {
dp1[i][j] = dp0[i][j-1]+dp1[i][j-1]-dp0[i][j-1-limit];
}
dp1[i][j] = (dp1[i][j] % mod+mod)%mod;
}
}
return (dp0[zero][one]+dp1[zero][one])%mod;
}
};
注意: 在对结果进行取余的时候要注意防止出现负数,因此要先加上一个
1
0
9
+
7
10^9+7
109+7再取余。如果不那么做,那么在dp0[i][j] = dp0[i-1][j]+dp1[i-1][j]-dp1[i-1-limit][j];
的时候,由于dp0[i-1][j]+dp1[i-1][j]
虽然比dp1[i-1-limit][j]
大,但是由于前一项取余之后可能很小,后一项取余之后也可能很大,因此相减可能出现负数,如果不处理可能导致最终的结果为负。