【leedcode】526. 优美的排列

113 阅读1分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

难度: 中等

题目描述

假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:

  1. 第 i 位的数字能被 i 整除
  2. i 能被第 i 位上的数字整除

现在给定一个整数 N,请问可以构造多少个优美的排列?

示例1:

输入: 2
输出: 2
解释: 

第 1 个优美的排列是 [1, 2]:
  第 1 个位置(i=1)上的数字是11能被 ii=1)整除
  第 2 个位置(i=2)上的数字是22能被 ii=2)整除

第 2 个优美的排列是 [2, 1]:
  第 1 个位置(i=1)上的数字是22能被 ii=1)整除
  第 2 个位置(i=2)上的数字是1ii=2)能被 1 整除

说明:

N 是一个正整数,并且不会超过15。

解题思路

回溯法

这道题是一道构造题,即构造一个长度为 N 的自然序列,满足整除关系: i % nums[i] = 0nums[i] % i = 0(i 为第 i 个位置)。 由于看到数据范围 N <= 15,因此很容易想到这道题用深搜(DFS)去做。

class Solution:
    def countArrangement(self, n: int) -> int:
        ret = 0
        matchs = collections.defaultdict(list)
        for i in range(1, n + 1):
            for j in range(1, n + 1):
                if i % j == 0 or j % i == 0:
                    matchs[i].append(j)
        # print(matchs)
        seen = set()
        def dfs(index):
            nonlocal ret
            if index > n: 
                ret += 1
                return

            for v in matchs[index]:
                if v not in seend:
                    seend.add(v)
                    dfs(index + 1)
                    seen.discard(v)
                
        dfs(1)
        return ret

思路二(带记忆DFS)

class Solution:
    def countArrangement(self, N: int) -> int:
        import functools

        @functools.lru_cache(None)
        def dfs(i, cur):  
            if i == N + 1:
                return 1
            res = 0
            for  k in range(N):
                num = 1 << k
                if not cur & num and ((k + 1) % i == 0 or i % (k + 1) == 0):
                    res += dfs(i + 1, cur | num)
            return res
                     
        return dfs(1, 0)