题目
假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:
- 第 i 位的数字能被 i 整除
- i 能被第 i 位上的数字整除
- 现在给定一个整数 N,请问可以构造多少个优美的排列?
示例1:
输入: 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。
题解
方法一:回溯法
因为N不会超过15,所以可以使用回溯法,不用担心超时问题。
构建备选数集合后, 依次不放回的选中某个数, 要求取出数满足一定条件, 求最终将集合中元素全部取出的方法的个数。
回溯模板:
a. 定义集合List left为当前状态下,存储可选数的备选元素集合(初始化为1~N的元素集合)。
b. 在 left 集合中选取第 i 个位置的元素时,遍历 left集合, 当遍历到的元素 x 满足条件:
x
%
i
=
=
0
∣
∣
i
%
x
=
=
0
x\%i==0 || i\%x==0
x%i==0∣∣i%x==0 时, 说明在当前位置, 取当前元素 x 可以满足要求,那么可以从备选元素集合中删除 x , 进入第 i+1 位的遍历, 此即递归的循环体;
c. 递归的退出条件即为: 剩余元素的集合left的集合大小等于0,此时的排列是题目要求求得的排列的一种。
class Solution {
int ans = 0;
public int countArrangement(int n) {
// 回溯法
List<Integer> left = new ArrayList<>(); //构建存储可选数的备选列表
for(int i = 1; i <= n; i++){ // 初始化
left.add(i);
}
dfs(left, 1); // left是备选列表,1是当前位置
return ans;
}
private void dfs(List<Integer> left, int index){
if(left.size() == 0){ // 说明所有数都放到了对应位置
ans++;
return;
}
for(int x : left){
if(x % index == 0 || index % x == 0){ // 该位置可以放x
List<Integer> copy = new ArrayList<>(left); // 这里不能先删再加,会打乱顺序,采用复制列表的方式
// List删除元素时传入数字时,默认按索引删除。如果需要删除Integer对象,调用remove(object)方法,需要传入Integer类型。
copy.remove(new Integer(x)); // 将当前元素从备选列表中删除
dfs(copy, index + 1);
}
}
}
}
力扣官方方法
采用了visited数组来标记是否使用,以及match数组来预处理获取每个位置满足要求的数。
class Solution {
List<Integer>[] match;
boolean[] vis;
int num;
public int countArrangement(int n) {
vis = new boolean[n + 1];
match = new List[n + 1];
for (int i = 0; i <= n; i++) {
match[i] = new ArrayList<Integer>();
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i % j == 0 || j % i == 0) {
match[i].add(j);
}
}
}
backtrack(1, n);
return num;
}
public void backtrack(int index, int n) {
if (index == n + 1) {
num++;
return;
}
for (int x : match[index]) {
if (!vis[x]) {
vis[x] = true;
backtrack(index + 1, n);
vis[x] = false;
}
}
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/beautiful-arrangement/solution/you-mei-de-pai-lie-by-leetcode-solution-vea2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。