该题解采用了动态规划与深度优先搜索(DFS)结合的方法来解决问题。首先对数组进行排序,利用排序的特性简化除法运算的条件检查。接着,构建一个图的表示方式,用一个整数数组g来表示节点之间的连接关系,其中g[i]的二进制中的第j位如果是1,表示nums[i]和nums[j]之间可以相互整除。然后,通过DFS遍历所有可能的排列组合,使用位掩码技术来表示当前已经选择的元素集合。最后,利用缓存机制(@cache)来优化重复计算,提高效率。
时间复杂度: O(n * 2^n)
空间复杂度: O(n + 2^n)
class Solution:
def specialPerm(self, nums: List[int]) -> int:
nums.sort() # 先对数组排序
r, mod = range(len(nums)), 10**9 + 7
g = [1 << i for i in r] # 初始化每个数自己的掩码
for i, j in combinations(r, 2): # 生成所有可能的两数组合
if nums[j] % nums[i] == 0: # 检查是否整除
g[i] |= 1 << j
g[j] |= 1 << i
ends = [i for i, b in enumerate(g) if b.bit_count() == 2] # 查找端点
if any(i.bit_count() == 1 for i in g) or len(ends) > 2: # 检查是否存在单独点或端点过多
return 0
def ones(mask): # 生成mask中所有为1的位的索引
while mask:
i = mask.bit_length() - 1
yield i
mask ^= 1 << i
@cache
def complete(mask): # 检查mask是否为一个完整的子图
return all(g[i] & mask == mask for i in ones(mask)) and factorial(mask.bit_count() - 1)
@cache
def unconnected(mask): # 检查是否有未连接的点
return any(g[i] & mask == 1 << i for i in ones(mask))
@cache
def dfs(start, mask): # 深度优先搜索
intersection = g[start] & mask
if intersection == 0:
return 0
if cm := complete(mask):
return cm * intersection.bit_count()
if unconnected(mask):
return 0
return sum(dfs(i, mask ^ (1 << i)) for i in ones(intersection))
universal = (1 << len(nums)) - 1
g.append(1 << ends[0] if ends else universal)
ans = dfs(-1, universal) % mod
return ans * 2 % mod if ends else ans