假设有从 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 整除
【思路】:
与全排列思路基本一致,最后加个判断即可。
注:如果每次都是搜到最后才判断,则会超时!
所以我们用一个剪枝的手法。
因为要想整个数组都是优美排列,必须保证,其子数组也是。
因此我们没有必要每次在最后时刻再判断,如果一开始就不是优美排列,就没有必要搜索下去了。
事实证明,这个剪枝策略带来的优化效果是巨大的!
【代码】:
/**
* @param {number} n
* @return {number}
*/
var isBeautiful = function(perm){
let bool = true;
for(let i =1;i < perm.length;i++){
if(perm[i] % i == 0 || i % perm[i] == 0) continue;
bool = false;
break;
}
return bool;
}
var dfs = function(k, n, vis, path, res, bool){
//关键剪枝,不用到最后一步再判断!
if(!isBeautiful(path)) return ;
if(k > n){
//judge
if(isBeautiful(path)){
bool.cnt++;
}
return ;
}
for(let i = 1;i <= n;i++){
if(vis[i] == 1) continue;
vis[i] = 1;
path.push(i);
dfs(k + 1, n, vis, path, res,bool);
path.pop();
vis[i] = 0;
}
}
var countArrangement = function(n) {
var vis = new Array(n + 1).fill(0);
var res = [];
var bool = {cnt:0};
dfs(1, n, vis, [-1], res, bool);
return bool.cnt;
};