1655. 分配重复整数
题目描述
给了一个数组nums,数组中最多有50个不同的值
再给了m个顾客的订单数组,数组元素ei的含义是第i个顾客需要有ei个相同的整数
问给的nums能不能满足以上所有顾客的要求?
f1-状态压缩+dp |
基本分析
- 人数m不超过10?用二进制表示能满足人的子集
- 具体地取哪些数字重要吗?值不重要,值出现的个数重要->用一个辅助数组cnt去存值出现的次数[1,1,2,2,1,3]转化为[3,2,1]
- 怎么统计某个子集需要的个数?针对订单为[2,3]情况,ssum[0]=0,ssum[1]=2,ssum[10]=3,ssum[11]=5。这里的5是需要的总和,但不一定要求某个cnt[i]一定要大于这个
- dp状态?f[i][j]表示考虑前i个数组,分配状态为j时,能不能满足要求
- dp边界?对所有的i,j=0时候表示不需要分配,此时都能满足
- 考虑转移?
- (1)先遍历数组维度i,前i个数字
- (2)再遍历状态维度。此时可能i-1就能满足j,这个时候直接转移退出j讨论;否则i-1不能满足,需要继续往下走
- (3)枚举j的子集,把j分为前i-1物品完成的状态prev和利用物品i完成的状态。通过遍历找到满足的情况时,f[i][j]为True。注意枚举子集的时候先把s设置为j,之后用 s = (s-1)&j实现
代码
class Solution: def canDistribute(self, nums: List[int], quantity: List[int]) -> bool: tmp = Counter(nums) cnt = [] for k, v in tmp.items(): cnt.append(v) n, m = len(cnt), len(quantity) mask = 1<<m ssum = [0] * mask for i in range(1, mask): for j in range(m): if i &(1<<j) != 0: ssum[i] = ssum[i-(1<<j)] + quantity[j] break print(ssum) f = [[False] * (mask) for _ in range(n)] for i in range(n): f[i][0] = True for i in range(n): for j in range(mask): if i>0 and f[i-1][j]: f[i][j] = True continue s = j while s: prev = j-s if i == 0: last = (prev ==0) else: last = f[i-1][prev] need = ssum[s]<=cnt[i] if last and need: f[i][j] = True break s = (s-1)&j return f[-1][-1]
复杂度
时间:
空间:
总结
- 看出频数重要,从给出的nums信息中处理出cnt
- 预处理出ssum数组,可以快速查处某个子集需要的相等数的个数
- dp中先枚举i个数组的维度;再枚举可能的组合j,对j判断i-1是不是已经满足,满足跳过j,不满足往下走;枚举j的子集,将j分为prev和s两部分,看是不是存在满足f[i-1][prev]==True和ssum[s]<=cnt[i]的关系
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现