- 状态压缩
假设有n个数,每个数有两种状态,用0和1表示。
总共有种状态,用来表示。
n = 16
mask = 1 << n
for s in range(mask):
for i in range(n):
if s & (1 << i): # s & (1 << i)表明第i个数尚未使用
pass
- 枚举子集
对于二进制状态s,可以用如下方法枚举s子状态
sub = s
while sub:
sub = (sub - 1) & s
时间复杂度:
- 最小不兼容性
给你一个整数数组 nums 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。
一个子集的 不兼容性 是该子集里面最大值和最小值的差。
请你返回将数组分成 k 个子集后,各子集 不兼容性 的 和 的 最小值 ,如果无法分成分成 k 个子集,返回 -1 。
子集的定义是数组中一些数字的集合,对数字顺序没有要求。
来源:LeetCode
链接:https://leetcode-cn.com/problems/minimum-incompatibility
参考解答:(本解法容易超时)
class Solution:
def minimumIncompatibility(self, nums: List[int], k: int) -> int:
n = len(nums)
if n == k:
return 0
m = n // k
dp = {}
for mask in range(1 << n):
bc = bin(mask).count('1')
if bc == m:
used = set()
flag = True
for i in range(n):
if mask & (1 << i):
if nums[i] in used:
flag = False
break
used.add(nums[i])
if flag:
dp[mask] = max(used) - min(used)
elif bc % m == 0:
sub = mask
while sub:
if sub^mask in dp and sub in dp:
if mask not in dp:
dp[mask] = dp[sub^mask] + dp[sub]
else:
dp[mask] = min(dp[mask], dp[sub^mask] + dp[sub])
sub = (sub - 1) & mask
return dp[(1 << n) - 1] if (1 << n) - 1 in dp else -1
- 完成所有工作的最短时间
给你一个整数数组 jobs ,其中 jobs[i] 是完成第 i 项工作要花费的时间。
请你将这些工作分配给 k 位工人。所有工作都应该分配给工人,且每项工作只能分配给一位工人。工人的 工作时间 是完成分配给他们的所有工作花费时间的总和。请你设计一套最佳的工作分配方案,使工人的 最大工作时间 得以 最小化 。
返回分配方案中尽可能 最小 的 最大工作时间 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-minimum-time-to-finish-all-jobs
参考解答:(本解法容易超时)
class Solution:
def minimumTimeRequired(self, jobs: List[int], k: int) -> int:
n = len(jobs)
dp = [[0] * (1 << n) for _ in range(k)]
for i in range(1 << n):
for j in range(n):
if i & (1 << j):
rest = i - (1 << j)
dp[0][i] = dp[0][rest] + jobs[j]
for i in range(1, k):
for j in range(1 << n):
s = j
dp[i][j] = dp[0][j]
while s:
rest = j - s
dp[i][j] = min(dp[i][j], max(dp[i-1][rest], dp[0][s]))
s = (s - 1) & j
return dp[-1][(1<<n)-1]