https://leetcode.com/problems/number-of-people-aware-of-a-secret/
DP再次教我做人。
这道题根本想不到用DP做,看到hint1的DP,瞬间恍然大悟。DP问题的难点在于,如何构造DP对象,这道题是个很好的例子。

个人解答

  1. const MOD = 1000000007
  2. func peopleAwareOfSecret(n int, delay int, forget int) int {
  3. dp := make([]int, forget)
  4. dp[0] = 1
  5. for i := 2; i <= n; i++ {
  6. for j := forget - 1; j > 0; j-- {
  7. dp[j] = dp[j - 1]
  8. }
  9. dp[0] = 0
  10. for j := delay; j < forget; j++ {
  11. dp[0] += dp[j]
  12. dp[0] %= MOD
  13. }
  14. }
  15. res := 0
  16. for i := 0; i < forget; i++ {
  17. res += dp[i]
  18. res %= MOD
  19. }
  20. return res
  21. }

题目分析

这道题是个很实际的问题,抽象的也很好,是个好题。乍一看,似乎是个找规律的题目,从传播中找到一个固定的模式,然后用一个通用的公式求出第n天的结果。不过,死活想不出来。
再想想,新的一天知道的人,依赖这一天可以传播的所有人,这一天已经知道的所有人,就是所有已知且还没有忘了的人。这种递推关系,有点DP的影子了。
然后想DP的对象和状态转移方程,最直白的,dp[i]表示第i天知道的所有人,但是这个信息不够,无法记录新增多少人,忘了多少人。考虑加一个信息:dp[i][j]表示第i天已经知道了j天的人。如果能这么想到,推出递推公式比较直观了。

  1. dp[i][j] = dp[i - 1][j - 1] // for j > 1
  2. dp[i][j] = sum(dp[i][delay...forget]) // for j = 0

j = 0表示刚知道,刚知道的人,也就是这一天能传播的人,也就是知道天数在[delay, forget) 区间的人了。
最后把所有第n天知道的人sum一下就好了,具体的看代码。