夯实算法-优美的排列

118 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 23 天,点击查看活动详情

题目:LeetCode

假设有从 1 到 n 的 n 个整数。用这些整数构造一个数组 perm下标从 1 开始),只要满足下述条件 之一 ,该数组就是一个 优美的排列 :

  • perm[i] 能够被 i 整除
  • i 能够被 perm[i] 整除

给你一个整数 n ,返回可以构造的 优美排列 的 数量 。

示例 1:

输入: n = 2
输出: 2
解释:
第 1 个优美的排列是 [1,2]:
    - perm[1] = 1 能被 i = 1 整除
    - perm[2] = 2 能被 i = 2 整除
第 2 个优美的排列是 [2,1]:
    - perm[1] = 2 能被 i = 1 整除
    - i = 2 能被 perm[2] = 1 整除

示例 2:

输入: n = 1
输出: 1

提示:

  • 1 <= n <= 15

解题思路

根据题意本题思路比较明晰,直接求出n的所有排列,并查看排列是否满足题目给出的条件,不满足则剪枝,满足则继续往下遍历,直到遍历的轨迹大小等于n

写出求数的全排序:

  • 先定义dfs函数,入参肯定有数的大小n, 集合track代表运行轨迹
  • 首先是回溯的退出条件: 当track的数量等于n时表明可以组成排序,res++
  • 接着从1到n遍历所有的数字num
  • 因为全排列不能包含重复数字,当track包含数组num时直接跳过
  • 将num加入track中,做选择
  • 递归遍历
  • 最后将track的末尾删除,撤销选择

代码实现

public static int count = 0;
public static int countArrangement(int n) {
    List < Integer > track = new ArrayList < > ();
    dfs(n, track);
    return count;
}

public static void dfs(int n, List < Integer > track) {
    if (track.size() == n) {
        count++;
        return;
    }
    for (int i = 1; i <= n; i++) {
        if (track.contains(i)) {
            continue;
        }
        track.add(i);
        if (i % track.size() == 0 || track.size() % i == 0) {
            dfs(n, track);
        }
        track.remove(track.size() - 1);
    }
}

运行结果

Snipaste_2023-02-26_21-46-13.png

复杂度分析

  • 空间复杂度:O(n)O(n)
  • 时间复杂度:O(n!)O(n!)

掘金(JUEJIN)  一起分享知识, Keep Learning!