LeeetCode--526. 优美的排列

526. 优美的排列

思路:
动态规划 + 状态压缩
状态压缩:
最多的数字个数是15,所以可以使用一个int型变量,每一位代表是否选择当前数字。mask代表选取的位置,由于是由0位开始的,所以第i位实际上是第i+1位数字。
动态规划:
每一次选取后,下一次选取在该次选取的基础上再次选取。
状态转移方程
在这里插入图片描述
当我们想要计算当前的f[mask]时,需要把前num(mask - 1) 放置好,,最后再将本次计算结果累加上去。我们需要依次枚举本次可以被放置的数,最后加起来。
最终的结果在f[2^n - 1] 这里呈现。

/**
 * 526. 优美的排列
 */

public class Solution526 {
  public int countArrangement(int n) {
    // 结果集个数  最多 2^N - 个
    // 用来存储中间结果,res[6] = res[000110] = 数字2、3在前两位时的完美排列数量
    int[] res = new int[1 << n];
    // 1 肯定能放在第一位,结果个数为1
    res[0] = 1;
    // mask 使用状态压缩,将数组压缩成一个数字
    for (int mask = 1; mask < (1 << n); mask++) {
      // num 二进制中数字1的个数,1代表当前数字可以存放,0代表当前数字不可以存放
      int num = Integer.bitCount(mask);
      // i + 1 代表当前的数字,i 代表 当前数字对应的在mask中间的位置
      // 遍历 mask 的每一位,仍以 mask = 100110 为例,此 mask 代表 2 3 6三个数字在排列的前三位
      // 求三个数字 2 3 6 的完美排列方式,则先确定2 3 6哪些数字能放到第三位,然后累加另外两个数字的完美排列数量来获得
      for (int i = 0; i < n; i++) {
        // mask & (1 << i) 检查当前位置是否被选取
        if ((mask & (1 << i)) != 0) {
          // ((num % (i + 1)) == 0 || (i + 1) % num == 0) 判断被选取的数字 i+1 能否放到位置 num 上,
          // 即:先从被选取的数字中找到能放到最高位 num 的数字,然后将剩余 num-1 个数字的完美排列方式累加到res[mask]中
          if (num % (i + 1) == 0 || (i + 1) % num == 0) {
            // 00010101 ^
            // 00000110 =
            // 00010011
            // mask ^ (1 << i) 将 mask 第 i 位设置为 0
            // 2 3 6,第三位可以为 6,则 res[100110] += res[000110] (2、3在前两位时的完美排列数量)
            // 2 3 6,第三位可以为 3,则 res[100110] += res[100010] (2、6在前两位时的完美排列数量)
            res[mask] += res[mask ^ (1 << i)];
          }
        }
      }
    }
    return res[1 << n - 1];
  }

  public static void main(String[] args) {
    Solution526 solution526 = new Solution526();
    System.out.println(solution526.countArrangement(6));
    System.out.println(solution526.countArrangement(12));
  }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值