1. 题目链接:526. 优美的排列
2. 题目描述:
假设有从 1 到 n 的 n 个整数。用这些整数构造一个数组
perm
(下标从 1 开始 ),只要满足下述条件 之一 ,该数组就是一个 优美的排列 :
perm[i]
能够被i
整除i
能够被perm[i]
整除给你一个整数
n
,返回可以构造的 优美排列 的 数量 。示例 1:
输入:n = 2 输出:2 解释: 第 1 个优美的排列是 [1,2]: - perm[1] = 1 能被 i = 1 整除 - perm[2] = 2 能被 i = 2 整除 第 2 个优美的排列是 [2,1]: - perm[1] = 2 能被 i = 1 整除 - i = 2 能被 perm[2] = 1 整除
示例 2:
输入:n = 1 输出:1
提示:
1 <= n <= 15
3. 解法(递归):
3.1 算法思路:
我们需要在每个位置上考虑所有的可能情况并且不能出现重复。通过深度优先搜索的方式,不断地枚举每个数在当前位置的可能性,并且回溯到上一个状态,直到枚举完所有的可能性,得到正确的结果。
我们需要定义一个变量来记录所有可能的排列数量,一个一维数组标记元素,然后从第一个位置开始进行递归
3.2 递归流程:
- 递归结束条件:当
pos
等于n+1
时,说明已经处理完所有的数字,将当前数组存入结果中 - 在每个递归状态中,枚举所有下标,若这个下标未被标记,并且满足题目条件之一:
- 将
check[i]
标记为true
- 对第
pos+1
个位置进行递归 - 将
check[i]
重新赋值为false
,表示回溯
- 将
3.3 C++算法代码:
c++
class Solution {
bool check[16]; // 用于记录每个数字是否已经被使用过
int ret; // 用于记录满足条件的排列的数量
public:
int countArrangement(int n) {
dfs(1, n); // 从第一个位置开始搜索
return ret; // 返回满足条件的排列的数量
}
void dfs(int pos, int n) {
if (pos == n + 1) { // 如果已经到达最后一个位置
ret++; // 找到一个满足条件的排列,将计数器加1
return; // 返回上一层递归
}
for (int i = 1; i <= n; i++) { // 遍历从1到n的所有数字
if (!check[i] && (pos % i == 0 || i % pos == 0)) { // 如果数字i未被使用过且满足排列的条件
check[i] = true; // 将数字i标记为已使用
dfs(pos + 1, n); // 继续搜索下一个位置
check[i] = false; // 将数字i标记为未使用,以便在其他路径中使用
}
}
}
};