1. 程式人生 > >leetcode 第k個排列 python

leetcode 第k個排列 python

60. 第k個排列

題目描述:*給出集合 [1,2,3,…,n],其所有元素共有 n! 種排列。
按大小順序列出所有排列情況,並一一標記,當 n = 3 時, 所有排列如下:
“123”
“132”
“213”
“231”
“312”
“321”
給定 n 和 k,返回第 k 個排列。
說明:
給定 n 的範圍是 [1, 9]。
給定 k 的範圍是[1, n!]。
示例 1:
輸入: n = 3, k = 3
輸出: “213”
示例 2:
輸入: n = 4, k = 9
輸出: “2314”*

1. 暴力法
可以用遞迴全排列,將所有的可能都加入到一個列表中,進行排序,找到第K個就行了,這裡就不做多述,因為時間複雜度太高了,肯定超時。
2.權值解法


有點像海明碼的感覺,以n=6,k=100為例,我們來定義一下他們的權值,下面我們來看張圖片
這裡寫圖片描述
當第六位確定之後,後面五位數最多能組成120個數(5!),也就是說圖上6所在的位置,1代表120,2代表240,以此類推。我們定義圖上6所在的位置的權值為120,當確定左邊兩位的時候,剩下四位最大可能組合為24種,我們定義其權值為24,剩下的就不一一說了,看上面的圖。
下面我們來舉個例子n=6,k=100;
首先n=6最大組合數是720,720>100說明6位數的組合數超過100,假定我們確定最高位為1
剩下的五位數最大組合數為120,120>100同理說明五位數的組合數超過100,同理我們可以判斷四位數不行。大家都知道當確定位數後,最高位越小這個數越小,所以證明上面的假定成立,最高位為1。下面就不一一解說了,次高位權值為24,在剩下的數中【2,3,4,5,6】選取6
(100/24=4點多,所以取第五位),確定兩位後現在我們來確定第三高位,用剩下的(餘數)4(100/24=4…..4)繼續除以其權值6等於零點幾,所以選剩下數列中第一位(2)。再繼續用上次的餘數4除以第四高位的權值2,等於2正好整除,選取剩下列表中的第二位【3,4,5】4,(正好整除的意思就是說在確定前面的高位的基礎上,後面剩餘得數選取他們的最大組合數就行了)所以,第五位第六位分別是5,3。最終我們可以得出第一百個數是(k=100)162453。自認說的不是很清楚,第一次寫部落格,如有疑問或建議歡迎回帖,謝謝。下面直接看程式碼。
這個程式碼的思路較清晰但是在LeetCode不能正常執行不知道是什麼原因,我試過了window系統上的python2.X、python3.X和Linux終端都能正常執行。我猜測是取天花那一步出問題了,如果你們有興趣可以加個if判斷,我就懶得寫了,之後我再複製一個我好早之前寫的程式碼,有點不清晰,但是能通過用時LeetCode上用時28ms。

import math
class Solution(object):
    def getPermutation(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: str
        """
        templist=[]#定義一個列表,用於裝放下面取出的數
        temp=[i for i in range(1,n+1)]#定義一個n位的列表1-n
        dicts={1:1,2:1,3:2,4:6,5:24,6:120,7:720,8:5040,9:40320,10:362880}#定義各位的權值
        for i in range(n,0,-1):
            s = math.ceil(k / dicts[i])#計算商值 取其天花
            templist.append(temp.pop(s - 1))#將對應數值,加入到templist中,並刪除在temp中取出得數,避免重複取出
            if k%dicts[i]==0:#判斷能整除
                templist.extend(temp[::-1])#將剩餘數反轉,即最大組合數
                break
            else:#如果不能整除,即將k值等於其餘數
                k%=dicts[i]
        return ''.join([str(i) for i in templist])#將列表中數字先轉化為str`

程式碼二

class Solution(object):
    def getPermutation(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: str
        """
        templist=[]
        temp=[i for i in range(1,n+1)]
        dicts={1:1,2:2,3:6,4:24,5:120,6:720,7:5040,8:40320,9:362880,10:3628800,11:39918600}
        for i in range(n-1,0,-1):
            if k<=dicts[i]:
                templist+=temp[:len(temp)-i]
                temp=temp[len(temp)-i:]
            else:
                if k==dicts[i+1]:
                    templist.append(temp[k//dicts[i]-1])
                    temp.pop(k//dicts[i]-1)
                    templist+=temp[::-1]
                    temp=[]
                    break
                else:
                    templist.append(temp[k // dicts[i]-1 if k%dicts[i]==0 else k // dicts[i] ])
                    temp.pop(k // dicts[i]-1 if k%dicts[i]==0 else k // dicts[i])
                    k = k % dicts[i]
                    if k==0:
                        templist += temp[::-1]
                        temp = []
                        break
        s1=''
        for s in templist+temp:
            s1+=str(s)
        return s1