698. 划分为k个相等的子集

题目描述

给出一个数组nums,问能不能分为k份,每份的和都相等,数组的长度不超过16

f1-状态压缩+记忆化搜索

基本分析

  1. 数组长度不超过16?暗示可以对选择情况用二进制进行表达
  2. 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
  3. 其他一些预处理的技巧?(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 // k
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,nO(n×2n)
空间:O(2n)

总结

  1. 其实还是从没选到选的顺序进行递推,只不过把后面当做了已知
f2-状态压缩+动态规划

基本分析

  1. 这里和存在哪里?用f[s]来表示s当前对应的%line的值,-1表示还没有选或者不能选,其余值对应dfs里面的p
  2. 往后递推的思路?和dfs中是类似的,(1)这里先遍历每个可能的s,s不满足就去下一个s;(2)如果s满足,去遍历可能的i和v,需要满足s中i处是0,且f[s]的值+v不超过均值,如果以上都满足了,如果新的ns没有更新,那么就更新他
  3. 最后怎么判断是不是满足要求?最后看填满时候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):
# 如果s状态不能满足,那么就下一个s
if f[s] == -1:
continue
# 遍历可能的数字
for i, v in enumerate(nums):
# 首先还是需要考虑s中不为1的位置
if s >> i & 1:
continue
# 其次和不能超
if f[s] + v > line:
continue
# 都满足了,就对新的ns进行更新,为什么需要判断f[ns]==-1的情况?可能是结果唯一,再更新没意义
ns = s | 1<<i
if f[ns] == -1:
f[ns] = (f[s] + v) % line
return f[-1] == 0

复杂度

时间:2n,nOn×2n
空间:O(2n)

总结

  1. 和dfs的区别在哪?(1)总的递推过程是类似的;(2)这里需要显式的先去遍历可能的所有s,dfs只是在最后和他的后续可能建立关系;(2)dfs中对和直接用参数进行传递,这里显式的定义了f数组,兼顾存和和判断是当前否当前可行的作用;(3)结束的时候,这个f[-1]需要判断和0的关系,dfs里面直接取到mask就返回True了?
posted @   zhangk1988  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示