先观察n的范围为[1,15],所以我们可以先用暴力的方式计算出所有答案,然后存入数组,直接O(1)获取答案。但全排列15的阶层太大了,内存会爆掉。
class Solution {
public static void main(String[] args) {
String[][] strings = new String[6][];
for (int i = 1; i <= 5; i++) {
strings[i] = new String[200];
}
strings[1][0] = "1";
System.out.println(strings[1][0]);
for (int i = 2; i <= 5; i++) {
String now = String.valueOf(i);
int cnt = 0;
for (String s : strings[i - 1]) {
if(s != null) {
int len = s.length();
for (int j = 0; j <= len; j++) {
strings[i][cnt] = s.substring(0, j) + now + s.substring(j);
System.out.print(strings[i][cnt] + " ");
cnt++;
}
} else {
break;
}
}
System.out.println();
}
}
}
计算出来如下:
class Solution {
public int countArrangement(int n) {
int[] ans = {0,1,2,3,8,10,36,41,132,250,700,750,4010,4237,10680,24679};
return ans[n];
}
}
然后就开始正规做法——状压dp了,
说实话,不看题解,我一定写不出来,真的离谱。
主要思路就是前n位的完美排列次数,前n位中所有能放到第n位的数字,将其中每一个数分别变为0的完美排列次数总和。也就是说,将能放在第n位的数放到第n位上,然后其他数完美排(已经计算过了)
class Solution {
public int countArrangement(int n) {
int len = 1<<n;
int[] ans = new int[len];
ans[0] = 1;
for(int mask = 1;mask < len; mask++) {
int num = Integer.bitCount(mask);
for(int i = 0;i < n;i++) {
if((mask & (1<<i)) != 0 && (num % (i+1) == 0 || (i+1) % num == 0)) {
ans[mask] += ans[mask ^ (1<<i)];
}
}
}
return ans[len - 1];
}
}