本题出自力扣题库第526题。题面大意如下:
假设有从1到n的n个整数。用这些整数构造一个数组 perm(下标从 1 开始),只要满足下述条件 之一,该数组就是一个优美的排列 : perm[i] 能够被 i 整除 i 能够被 perm[i] 整除 1 << n << 15
示例:
输入:n = 2
输出:2
解释:两个符合条件的排列: [1,2]和[2,1]
题解:
本题是个典型的递归加DP的应用,根据题面给出的限制条件,n的最大值为15,因此我们可以使用一个整数变量来作为记录某个数字是否被用过的bitmap。递归过程从位置1开始,使用一个1到n的循环来依次检查各个数字,如果某个数字尚未用过,其满足优美排列的要求,那我们就将bitmap中对应该数字的比特位清零,以表示该数字已被用过,然后递归调用下一个位置,当所有位置都被填上数字后,就表明找到了一个优美排列。
递归实现之后,再加上DP数组用于缓存计算结果以避免重复计算。
Java代码如下:
class Solution {
Integer[][] dp;
public int countArrangement(int n) {
int bitmap = (1 << n) - 1;
dp = new Integer[n + 1][bitmap + 1];
return helper(1, bitmap, n);
}
private int helper(int posiiton, int bitmap, int n) {
if (posiiton > n) {
return 1;
}
if (dp[posiiton][bitmap] != null) {
return dp[posiiton][bitmap];
}
int count = 0;
for (int i = 1; i <= n; i ++) {
int check = 1 << (i - 1);
if ( (bitmap & check) == 0) {
continue;
}
if ((posiiton >= i && posiiton % i == 0) || (i > posiiton && i % posiiton == 0)) {
count += helper(posiiton + 1, bitmap - check, n);
}
}
return dp[posiiton][bitmap] = count;
}
}