LC 100293. 找出所有稳定的二进制数组 II
https://leetcode.cn/problems/find-all-possible-stable-binary-arrays-ii/description/
这里看了一下提示,提示给出的思路比较明显:
Let `dp[x][y][z = 0/1]` be the number of stable arrays with exactly `x` zeros, `y` ones, and the last element is `z`. (0 or 1). `dp[x][y][0] + dp[x][y][1]` is the answer for given `(x, y)`.
If we have already placed `x` 1 and `y` 0, if we place a group of `k` 0, the number of ways is `dp[x-k][y][1]`. We can place a group with size `i`, where `i` varies from 1 to `min(limit, zero - x)`. Similarly, we can solve by placing a group of ones.
Speed up the calculation using prefix arrays to store the sum of `dp` states.
但是在写代码的时候发现了许多问题,主要体现在想维护一个二维的前缀。但是好像这个东西不太work. 因为不太好维护这个二维前缀的更新顺序。实际上这个代码只需要维护一个一维的前缀就好。
另外一个问题就是没有参考实现,因为之前一直纠结在前缀怎么更新上,也不太好调试。后面有个思路就是先用brute force方式来编写代码,然后再这个brute force上观察代码结构,然后来优化代码,这个做法其实是挺不错的。
用brute force的代码如下,可以看到下面在求解cost的时候去遍历了,因为这个时候不知道怎么维护前缀
class Solution:
def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
import numpy as np
dp = np.zeros((zero + 1, one + 1, 2), np.int64).tolist()
MOD = 10 ** 9 + 7
# dp[x][y][z] -> x 0, y 1, endswith z[0/1]
# place k zeros in a group.
# dp[x][y][0] = sum (dp[x-k][y][1]) k = [1 .. min(x, limit)]
# dp[x-k][y][1] + dp[x-(k+1)[y][1] + .. dp[x-1][y][1]
# acc[x][y][1] - acc[x-k][y][1]
for k in range(1, min(zero, limit) + 1):
dp[k][0][0] = 1
for k in range(1, min(one, limit) + 1):
dp[0][k][1] = 1
for x in range(zero + 1):
for y in range(one + 1):
# try z = 0
if True:
k = min(x, limit)
cost = 0
for z in range(1, k + 1):
cost += dp[x - z][y][1]
dp[x][y][0] = (dp[x][y][0] + cost)
# try z = 1
if True:
k = min(y, limit)
cost = 0
for z in range(1, k + 1):
cost += dp[x][y - z][0]
dp[x][y][1] = (dp[x][y][1] + cost)
ans = dp[zero][one][0] + dp[zero][one][1]
ans = ans % MOD
return ans
然后再这个代码基础上,可以观察 z=0 的时候其实y没有变动,我们需要维护一个x的前缀和。而z=1的时候,x没有变动,这里可以直接使用滑动窗口来实现。有了正确的代码+TestCases做保证,这个重构起来就比较容易了。
class Solution:
def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
import numpy as np
dp = np.zeros((zero + 1, one + 1, 2), np.int64).tolist()
MOD = 10 ** 9 + 7
# dp[x][y][z] -> x 0, y 1, endswith z[0/1]
# place k zeros in a group.
# dp[x][y][0] = sum (dp[x-k][y][1]) k = [1 .. min(x, limit)]
for k in range(1, min(zero, limit) + 1):
dp[k][0][0] = 1
for k in range(1, min(one, limit) + 1):
dp[0][k][1] = 1
acc = [0] * (one + 1)
for x in range(zero + 1):
# try z = 0
k = min(x, limit)
for y in range(one + 1):
acc[y] += dp[x - 1][y][1] if x >= 1 else 0
if x > k:
acc[y] -= dp[x - k - 1][y][1]
cost = acc[y]
dp[x][y][0] = (dp[x][y][0] + cost)
# try z = 1
cost = 0
for y in range(one + 1):
cost += dp[x][y - 1][0] if (y >= 1) else 0
k = min(y, limit)
if y > k:
cost -= dp[x][y - k - 1][0]
dp[x][y][1] = (dp[x][y][1] + cost)
ans = dp[zero][one][0] + dp[zero][one][1]
ans = ans % MOD
return ans