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