LeetCode 第 60 題:第 k 個排列(回溯、鏈表)

地址:https://leetcode-cn.com/problems/permutation-sequence/
我寫的題解地址:https://leetcode-cn.com/problems/permutation-sequence/solution/hui-su-jian-zhi-python-dai-ma-java-dai-ma-by-liwei/

思路:從高到低確定每一位數字,這裏可以使用“回溯”方法中的“剪枝”技巧。

方法一:藉助“回溯”方法中的“剪枝”技巧

Java 代碼:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Solution {

    /**
     * 記錄數字是否使用過
     */
    private boolean[] used;

    /**
     * 階乘數組
     */
    private int[] factorial;

    private int n;
    private int k;
    /**
     * 從根結點到葉子結點的路徑
     */
    private List<Integer> path;

    public String getPermutation(int n, int k) {
        this.n = n;
        this.k = k;
        used = new boolean[n + 1];
        Arrays.fill(used, false);

        // 計算階乘數組
        factorial = new int[n + 1];
        factorial[0] = 1;
        for (int i = 1; i <= n; i++) {
            factorial[i] = factorial[i - 1] * i;
        }

        path = new ArrayList<>(n);
        dfs(0);

        StringBuilder stringBuilder = new StringBuilder();
        for (Integer c : path) {
            stringBuilder.append(c);
        }
        return stringBuilder.toString();
    }

    /**
     * @param index 在這一步之前已經選擇了幾個數字,其值恰好等於這一步需要確定的索引位置
     * @return
     */
    private void dfs(int index) {
        if (index == n) {
            return;
        }

        // 還未確定的數字的全排列的個數,第 1 次進入的時候是 n - 1
        int cnt = factorial[n - 1 - index];
        for (int i = 1; i <= n; i++) {
            if (used[i]) {
                continue;
            }
            if (cnt < k) {
                k -= cnt;
                continue;
            }
            path.add(i);
            used[i] = true;
            dfs(index + 1);
        }
    }
}

方法二:模擬鏈表直接計算求解

事實上,上面的過程也可以循環實現,只不過需要藉助一個列表,每次選出一個數,就將這個數從列表裏面拿出。因爲這個列表要支持頻繁的刪除操作,因此使用雙鏈表,在 Java 中 LinkedList 就是使用雙鏈表實現的。

作者:liweiwei1419
鏈接:https://leetcode-cn.com/problems/permutation-sequence/solution/hui-su-jian-zhi-python-dai-ma-java-dai-ma-by-liwei/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

Java 代碼:

import java.util.LinkedList;
import java.util.List;

public class Solution {

    public String getPermutation(int n, int k) {
        // 注意:相當於在 n 個數字的全排列中找到索引爲 k - 1 的那個數,因此 k 先減 1
        k --;

        int[] factorial = new int[n];
        factorial[0] = 1;
        // 先算出所有的階乘值
        for (int i = 1; i < n; i++) {
            factorial[i] = factorial[i - 1] * i;
        }

        // 因爲要頻繁做刪除,使用鏈表
        List<Integer> nums = new LinkedList<>();
        for (int i = 1; i <= n; i++) {
            nums.add(i);
        }

        StringBuilder stringBuilder = new StringBuilder();

        // i 表示剩餘的數字個數,初始化爲 n - 1
        for (int i = n - 1; i >= 0; i--) {
            int index = k / factorial[i] ;
            stringBuilder.append(nums.remove(index));
            k -= index * factorial[i];
        }
        return stringBuilder.toString();
    }
}
發佈了449 篇原創文章 · 獲贊 336 · 訪問量 124萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章