0
点赞
收藏
分享

微信扫一扫

优美的排列

鲤鱼打个滚 2021-09-21 阅读 77
今日算法
题目描述:

假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:
第 i 位的数字能被 i 整除
i 能被第 i 位上的数字整除
现在给定一个整数 N,请问可以构造多少个优美的排列?

示例1:
说明:
题目分析:
  1. 条件一:第 i 位的数字能被 i 整除,条件二:i 能被第 i 位上的数字整除
    • 假设数组arr索引i,则 arr[i] % i == 0 || i % arr[i] == 0,需要满足其中一个。
  2. N 是一个正整数,并且不会超过15。
    • n的最大值15,小于int的32位,这代表可以使用状态压缩的方式来记录当前索引位置是否已被使用。
思路一:
代码实现:
class Solution {
    public int result;
    public boolean[] flag;
    public int countArrangement(int n) {
       result = 0;
       flag = new boolean[n + 1];
       dfs(1, n);
       return result;
    }
    public void dfs(int idx, int n) {
        if (idx > n) { // 超过最大数字n,返回。
            result++; // 
            return;
        }
        for (int i = 1; i <= n; i++) {
            if (!flag[i] && (idx % i == 0 || i % idx == 0)) {
                flag[i] = true; // 数组该索引位置已经存放了数字
                dfs(idx + 1, n); // 下一个数字
                flag[i] = false; // 删除该索引位置存放的数字
            }
        }
    }
}
思路二:

因为n的最大值只有15,因此可以使用状态压缩的方式来记录已经被使用的数组索引。

  • 索引i位置是否已被使用:
    • (1 << i) & state == 0 未被使用
    • (1 << i) & state == 1 已被使用
  • 标记索引i位置为使用状态:
    • (1 << i) | state
  • 所有位置是否都被使用
    • state ==(1 << n) - 1
代码实现:
class Solution {
    public int result;
    public int countArrangement(int n) {
       result = 0;
       dfs(1, n, 0);
       return result;
    }
    public void dfs(int idx, int n, int state) {
        if (state == ((1 << n) - 1)) { // 数组所有位置都被使用
            result++; 
            return;
        }
        for (int i = 1; i <= n; i++) {
            if (((1 << (i - 1)) & state) == 0 && (idx % i == 0 || i % idx == 0)) {
                dfs(idx + 1, n, ((1 << (i - 1)) | state)); // 下一个数字
            }
        }
    }
}
思路三:

通过观察思路二,可以发现有很多相同场景,反复进行了遍历,可以记录下来。避免重复递归。

代码实现:
class Solution {
    public int result;
    public int[][] arr;
    public int countArrangement(int n) {
       result = 0;
       arr = new int[n + 1][1 << n];
       result = dfs(1, n, 0);
       return result;
    }
    public int dfs(int idx, int n, int state) {
        if (state == (1 << n) - 1) return 1; // 所有数字都已经被使用
        if (arr[idx][state] != 0) return arr[idx][state]; // 数组索引idx,索引使用位置状态state的情况已经遍历过,直接返回

        int temp = 0;
        for (int i = 1; i <= n; i++) {
            if (((1 << (i - 1)) & state) == 0 && (idx % i == 0 || i % idx == 0)) {
                temp += dfs(idx + 1, n, ((1 << (i - 1)) | state)); // 下一个数字
            }
        }

        arr[idx][state] = temp; // 记录索引idx,数组索引使用状态state时的数量。
        
        return temp;
    }
举报

相关推荐

0 条评论