Dynamic Programming学习笔记 (46) - 优美的排列 (力扣# 526)

116 阅读1分钟

本题出自力扣题库第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;
    }
}