Leetcode_526_优美的排列_状压dp

先观察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];
    }
}

你可能感兴趣的:(动态规划,daily_algorithm,leetcode)