【Leetcode】60. 第k個排列

題目

給出集合 [1,2,3,…,n],其全部元素共有 n! 種排列。java

按大小順序列出全部排列狀況,並一一標記,當 n = 3 時, 全部排列以下:python

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

給定 n 和 k,返回第 k 個排列。app

說明:性能

給定 n 的範圍是 [1, 9]。
給定 k 的範圍是[1, n!]。
示例 1:ui

輸入: n = 3, k = 3
輸出: "213"

示例 2:spa

輸入: n = 4, k = 9
輸出: "2314"

題解

這道題還蠻有意思的,我首先一看,這不是backtrack的經典題目嗎? backtrack的剪枝能夠參看相關文章中有詳細的step-by-step的流程..net

  1. 從小到大把數排好;
  2. 用backtrack的方法遍歷,每次遍歷到一個全排列那麼結果,count+1;
  3. 遍歷到n就return輸出
  4. 因爲用的是backtrack,後面 count > k的狀況都直接return掉;

而後用java寫了一個版本,尚未剪枝就ac啦.code

class Solution {
int count = 0;
    List<Integer> finalRes;
    public String getPermutation(int n, int k) {
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = i + 1;
        }
        //第幾個解.
        List<Integer> resTemp = new ArrayList<>();
        boolean[] haveSeen = new boolean[n];
        backtrack(nums, k, resTemp, haveSeen);
        StringBuilder res = new StringBuilder();
        for (Integer i : finalRes) {
            res.append(i);
        }
        return res.toString();
    }

    public void backtrack(int[] nums, int k, List<Integer> tempIndex, boolean[] haveSeen) {
        if (tempIndex.size() == nums.length) {
            count++;
        }
        if (count == k && tempIndex.size() == nums.length) {
            finalRes = new ArrayList<>(tempIndex);
            return;
        } else if (count < k && tempIndex.size() == nums.length) {
            tempIndex = new ArrayList<>();
        }
        for (int i = 0; i < nums.length; i++) {
            if (haveSeen[i]) {
                continue;
            }
            tempIndex.add(nums[i]);
            haveSeen[i] = true;
            backtrack(nums, k, tempIndex, haveSeen);
            haveSeen[i] = false;
            tempIndex.remove(tempIndex.size() - 1);
        }
    }
}

因爲前幾天後臺有同窗反饋,但願給出java版本的題解。因此又動手寫了一個python版本.ci

class Solution:
    def getPermutation(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: str
        """
        global count
        global finalRes
        count = 0
        finalRes = []

        def backtrack(nums, k, resTemp, haveSeen):
            global count
            global finalRes
            if count > k:
                return
            if len(resTemp) == len(nums):
                count += 1
            if count == k and len(resTemp) == len(nums):
                finalRes = [str(_) for _ in resTemp]
                return
            elif count < k and len(resTemp) == len(nums):
                resTemp = []
            for i in range(0, len(nums)):
                if count > k:
                    break
                if haveSeen[i]:
                    continue
                resTemp.append(nums[i])
                haveSeen[i] = True
                backtrack(nums, k, resTemp, haveSeen)
                haveSeen[i] = False
                resTemp.pop()

        backtrack([_ + 1 for _ in range(0, n)], k, [], [False for _ in range(0, n)])
        return "".join(finalRes)

後來這個版本提交的時候我覺得能夠洗洗睡啦.
結果,臥槽,竟然換一種語言就超時啦~~rem

image

這卻是個意外.難道個人python寫的有性能問題,不該該啊,不是:

人生苦短,我用python

我就繼續想剪枝,還能怎麼剪枝?

剪枝是啥,不就是跳過某些步驟嗎?

那哪些步驟能夠跳過呢.

4的全排列是:
1 + {2,3,4}全排列
2 + {1,3,4}全排列
3 + {1,2,4}全排列
4 + {1,2,3}全排列

彷佛能夠轉化成子問題啊.

因爲題目只要求出第幾個,咱們再看看個數的規律

1 + {2,3,4}全排列(3!個)
2 + {1,3,4}全排列(3!個)
3 + {1,2,4}全排列(3!個)
4 + {1,2,3}全排列(3!個)

這就很好了呀~

具體來講是:

  • n 個數字有 n!種全排列,每種數字開頭的全排列有 (n - 1)!種。
  • 因此用 k / (n - 1)! 就能夠獲得第 k 個全排列是以第幾個數字開頭的。
  • 用 k % (n - 1)! 就能夠獲得第 k 個全排列是某個數字開頭的全排列中的第幾個。

數學之美啊,有木有。
而後就快速實現了python的code AC了.

class Solution:
    def getPermutation(self, n, k):
        nums = [str(_ + 1) for _ in range(0, n)]
        if k == 1:
            return "".join(nums)

        fact = 1
        for i in range(2, n):
            fact *= i

        round = n - 1
        k -= 1
        finalRes = []
        while round >= 0:
            index = int(k / fact)
            k %= fact
            finalRes.append(nums[index])
            nums.remove(nums[index])
            if round > 0:
                fact /= round
            round -= 1
        return "".join(finalRes)

每日英文

  • pulicity (n.) 曝光度,知名度

    • enhanace the ~ of yourself 提升本身的知名度
  • publication (n.) 刊物,發表
  • Publicize (v.) 宣傳

    • issue (v.) 發表
  • People's Republic Of China
  • in public
  • Republicans (n.)共和主義者
  • mass (n.)羣衆 (v.)彙集 (a.集中的)

    • masses of = many
  • civilian (a.)平民

    • civil law 民法

相關閱讀

Leetcode名企之路

相關文章
相關標籤/搜索