优美的排列
- 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. 编辑距离