题目描述
给出一个数组nums,问能不能分为k份,每份的和都相等,数组的长度不超过16
基本分析
- 数组长度不超过16?暗示可以对选择情况用二进制进行表达
- dfs的过程需要怎么实现?(1)参数就是当前的选择情况和对应的和;(2)最终退出条件就是s取到了mask,可以返回True;(3)对当前的s,需要在nums中逐个去遍历i和v,需要满足一些条件(s中i位置还是0并且p+v不能超均值),如果以上都满足了,那么dfs(s,p)就和dfs(ns, np)一条战线了;(4)如果找完了nums,都不能满足,就返回False
- 其他一些预处理的技巧?(1)和要整除(2)某个元素不能超过均值(3)对nums排序某些情况能减枝
代码
| class Solution: |
| def canPartitionKSubsets(self, nums: List[int], k: int) -> bool: |
| n = len(nums) |
| total = sum(nums) |
| if total % k != 0: |
| return False |
| line = total |
| nums.sort() |
| if nums[-1] > line: |
| return False |
| mask = (1<<n) - 1 |
| |
| @cache |
| def dfs(s, p): |
| # 选完了 |
| if s == mask: |
| return True |
| for i, v in enumerate(nums): |
| # s中i处需要没选,是0 |
| if s>>i & 1: |
| continue |
| # 大可以直接减枝,后面肯定不满足 |
| if p + v > line: |
| break |
| # 如果后续能满足,那么s时候可以满足 |
| if dfs(s | 1<<i, (p+v)%line): |
| return True |
| return False |
| |
| return dfs(0, 0) |
复杂度
时间:状态个数是2n,每个状态尝试n次,最终是O(n×2n)
空间:状态数组的开销是O(2n)
总结
- 其实还是从没选到选的顺序进行递推,只不过把后面当做了已知
基本分析
- 这里和存在哪里?用f[s]来表示s当前对应的%line的值,-1表示还没有选或者不能选,其余值对应dfs里面的p
- 往后递推的思路?和dfs中是类似的,(1)这里先遍历每个可能的s,s不满足就去下一个s;(2)如果s满足,去遍历可能的i和v,需要满足s中i处是0,且f[s]的值+v不超过均值,如果以上都满足了,如果新的ns没有更新,那么就更新他
- 最后怎么判断是不是满足要求?最后看填满时候f[-1]的值,如果是-1或者其他非0的值,那就不满足
代码
| class Solution: |
| def canPartitionKSubsets(self, nums: List[int], k: int) -> bool: |
| n = len(nums) |
| total = sum(nums) |
| if total % k != 0: |
| return False |
| line = total // k |
| nums.sort() |
| if nums[-1] > line: |
| return False |
| mask = 1<<n |
| f = [-1] * mask |
| f[0] = 0 |
| |
| |
| for s in range(mask): |
| |
| if f[s] == -1: |
| continue |
| |
| for i, v in enumerate(nums): |
| |
| if s >> i & 1: |
| continue |
| |
| if f[s] + v > line: |
| continue |
| |
| ns = s | 1<<i |
| if f[ns] == -1: |
| f[ns] = (f[s] + v) % line |
| return f[-1] == 0 |
复杂度
时间:状态个数是2n,每个状态尝试n次,因此O(n×2n)
空间:状态数组空间开销是O(2n)
总结
- 和dfs的区别在哪?(1)总的递推过程是类似的;(2)这里需要显式的先去遍历可能的所有s,dfs只是在最后和他的后续可能建立关系;(2)dfs中对和直接用参数进行传递,这里显式的定义了f数组,兼顾存和和判断是当前否当前可行的作用;(3)结束的时候,这个f[-1]需要判断和0的关系,dfs里面直接取到mask就返回True了?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现