优美的排列
题目描述:
假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:
第 i 位的数字能被 i 整除
i 能被第 i 位上的数字整除
现在给定一个整数 N,请问可以构造多少个优美的排列?
示例:
输入: 2
输出: 2
解释:
第 1 个优美的排列是 [1, 2]:
第 1 个位置(i=1)上的数字是1,1能被 i(i=1)整除
第 2 个位置(i=2)上的数字是2,2能被 i(i=2)整除
第 2 个优美的排列是 [2, 1]:
第 1 个位置(i=1)上的数字是2,2能被 i(i=1)整除
第 2 个位置(i=2)上的数字是1,i(i=2)能被 1 整除
提示:
- N 是一个正整数,并且不会超过15。
解法
比较典型的回溯问题,对于位置 k,它的候选值需要满足整除 k 或被 k 整除。所以我们只需要从第一个位置开始,用一个数组记录每个数字的使用情况,在没有使用的数字中,如果包含该位置的候选值,继续往下回溯;若不包含则停止回溯;直到 n 个位置都被填充。
代码
class Solution:
def countArrangement(self, n: int) -> int:
# 每个数字的使用情况,True-未使用,False-已使用
flag = [True for i in range(n + 1)]
# 每个位置的候选值
alternative_num = [[j for j in range(1, n + 1) if i % j == 0 or j % i == 0] for i in range(1, n + 1)]
return self.dfs(n, 1, flag, alternative_num)
def dfs(self, n, k, flag, alternative_num):
if k > n: # 停止条件
return 1
nums = alternative_num[k - 1] # 当前位置的候选值 list
res = 0
for num in nums:
if flag[num]: # 如果该候选值未被使用,往下回溯
flag[num] = False
res += self.dfs(n, k + 1, flag, alternative_num)
flag[num] = True
return res
测试结果
执行用时:364 ms, 在所有 Python3 提交中击败了 82.72% 的用户
内存消耗:15.1 MB, 在所有 Python3 提交中击败了 26.75% 的用户
说明
算法题来源:力扣(LeetCode)