题目:原题链接(困难)
标签:动态规划
解法 | 时间复杂度 | 空间复杂度 | 执行用时 |
---|---|---|---|
Ans 1 (Python) | O ( N K 2 ) O(NK^2) O(NK2) | O ( N K ) O(NK) O(NK) | 超出时间限制 |
Ans 2 (Python) | O ( N K ) O(NK) O(NK) | O ( N K ) O(NK) O(NK) | 324ms (98.75%) |
Ans 3 (Python) |
解法一(记忆化递归):
MOD = 10 ** 9 + 7
# 计算可能用到的阶乘列表
factorials = [1]
factorials_inv = [1] # 阶乘的乘法逆元
for num in range(1, 1001):
factorials.append((factorials[-1] * num) % MOD)
factorials_inv.append(pow(factorials[-1], MOD - 2, MOD))
def comb(n, m):
return factorials[n] * factorials_inv[m]
@functools.lru_cache(maxsize=None)
def count(n, k):
# 如果需要看到的比有的多:无法实现
if n < k:
return 0
# 当前列表中所有都必须看到:有序递增
if n == k:
return 1
# 当前列表中只能被看到1个:第1个为最大的,后面全排列
if k == 1:
return factorials[n - 1]
# 当前列表中1个都不能被看到:无法实现
if k == 0:
return 0
# 计算第一个可以放置的最大的数
first_max = n - k + 1
ans = 0
for i in range(1, first_max + 1):
# 计算比第1个位置小的数量
smaller = i - 1
# 计算比第1个位置大的数量
bigger = n - i
# 后面排列的能看见的情况总数
num1 = count(bigger, k - 1)
# 把n个比第1个位置小的随意插入m个比第1个位置大的数中
# n = smaller
# m = bigger+1
if smaller == 0:
v2 = 1
else:
# n = smaller + bigger ; m = bigger
v2 = factorials[smaller + bigger] * factorials_inv[bigger] * factorials_inv[smaller]
num2 = num1 * factorials[smaller] * v2
# print([n, k], ":", i, "->", [bigger, k - 1], "->", num1, ",", v1, v2, "->", num2)
ans += num2 % MOD
return ans % MOD
class Solution:
def rearrangeSticks(self, n: int, k: int) -> int:
return count(n, k)
解法二(动态规划):
MOD = 10 ** 9 + 7
dp = [[0] * 1001 for _ in range(1001)]
dp[0][0] = 1
for k in range(1, 1001):
for n in range(k, 1001):
# 把最小的放到第1个的情况
v1 = dp[n - 1][k - 1]
# 把最小的放到第1个以后位置(n-1个选择)的情况
v2 = (n - 1) * dp[n - 1][k]
dp[n][k] = (v1 + v2) % MOD
class Solution:
def rearrangeSticks(self, nn: int, kk: int) -> int:
return dp[nn][kk]