LC 1655. 分配重复整数
https://leetcode-cn.com/problems/distribute-repeating-integers/
这是典型的装箱问题,但是我忘记了动态规划的算法。写了一个粗糙的记忆化搜索,过了但是时间很长。
看了题解,想起来要用动态规划。 `dp[i][st]` 表示前面i个订单是否可以满足用st表示的顾客子集。另外学到一个奇怪的知识,就是这个算法时间复杂度是O(n*3^m).
至于这个3^m是怎么来的,可以这么考虑内部循环:
- st中有k个元素的个数是C(m, k)
- k的范围是 `0..m`.
所以内循环次数是 `C(m,k)*2^k. k=0..m`, 这个式子的结果是3^m.
class Solution2: def canDistribute(self, nums: List[int], quantity: List[int]) -> bool: from collections import Counter cnt = Counter(nums) values = list(cnt.values()) values.sort() quantity.sort() values = [x for x in values if x >= quantity[0]] if not values: return False if values[-1] < quantity[-1]: return False n, m = len(values), len(quantity) SUM = [0] * (1 << m) for i in range(1 << m): acc = 0 for j in range(m): if (i >> j) & 0x1: acc += quantity[j] SUM[i] = acc DP = [[0] * (1 << m) for _ in range(n + 1)] DP[0][0] = 1 for i in range(n): for j in range(1 << m): st = j ok = 0 if DP[i][j]: DP[i + 1][j] = 1 continue while st > 0: if SUM[st] <= values[i] and DP[i][j - st]: ok = 1 break st = (st - 1) & j DP[i + 1][j] = ok ans = DP[n][-1] return bool(ans)