优美的排列
- leetcode526. 优美的排列
- 题目描述
- 接替思路
- 代码演示:
- 动态规划专题
leetcode526. 优美的排列
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/beautiful-arrangement
题目描述
假设有从 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
接替思路
我们先求出每个位置上能放置那些数字,每个位置能放的数字,用一个数组保存起来:
我们以4 为例:
1.位置可以放1,2,3,4
2.位置可以放,1,2,4
3.位置可以放1,3
4,位置可以放1,4
四个位置排列组合,
每个位置上的数字不能重复,我们要排列组合这四个位置上的数字,并且去重,就可以用回溯算法解答了.
回溯过程中,我们可以用 visvis 数组标记哪些数被使用过,每次我们选中一个数 x,我们就将 flag[x] 标记为 true,回溯完成后,我们再将其置为 falsefalse。
特别地,为了优化回溯效率,我们可以预处理每个位置的符合条件的数有哪些,用二维数组 ans 保存。当我们尝试向位置 index放入数时,我们只需要遍历 ans[index] 即可。
回溯算法的框架:
result = []
def process(选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
代码演示:
package test.day100;
import test.day12.Demo02_IsBST;
import java.util.ArrayList;
import java.util.List;
/**
* 优美的排列
*/
public class Test31 {
List<Integer>[] ans ;
boolean[]flag;
int num;
/**
* 优美的排列
* @param n
* @return
*/
public int countArrangement(int n) {
ans = new List[n + 1];
flag = new boolean[n + 1];
ans[0] = new ArrayList<Integer>();
//每个位置能放置哪些数字,提前初始化出来.
for (int i = 1; i <= n;i++){
ans[i] = new ArrayList<>();
for (int j = 1;j <= n;j++){
if (i % j == 0 || j % i == 0){
ans[i].add(j);
}
}
}
process(n,1);
return num;
}
/**
* 回溯算法
* @param n
* @param index
*/
public void process(int n,int index){
//选完n个数满足 返回
if (index == n + 1){
num++;
return;
}
//选择列表
for (int x : ans[index]){
//去重,没选过的数字才可以选择
if (!flag[x]){
//选择
flag[x] = true;
process(n,index + 1);
//撤销选择
flag[x] = false;
}
}
}
}
动态规划专题
leetcode464. 我能赢吗
leetcode97. 交错字符串
leetcode474. 一和零
leetcode583. 两个字符串的删除操作
leetcode514. 自由之路
leetcode887. 鸡蛋掉落
leetcode72. 编辑距离