iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0
佛心分享-刷題不只是刷題

Leecode刷題系列 第 11

D12:60Permutation Sequence

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240926/20169309JW8XSZ4aDw.png
這題給定 n 和 k 的情況,返回 n! 個排列的第 k 個排列,因為排列數的成長很快速,如果逐一生成所有排列再找到第 k 個,效率會超低,所以需要一個更好的方式,直接算出第 k 個排列。

想法:
理解排列結構,每個位置的數字選擇受之前選擇的影響,例如:假設有 3 個數字 [1, 2, 3],總共有 6 種排列。固定第一個數字:
1 開頭,有 2! = 2 種排列:[123, 132]
2 開頭,也有 2 種排列:[213, 231]
3 開頭,有 2 種排列:[312, 321]
這表示,可以根據 k 的值,推出第一個數字是什麼,然後把問題縮小到剩下的數字,用階乘來算位置,可以透過 k // (n-1)! 來確定第 k 個排列的第一個數字,再用 k % (n-1)! 繼續算下一個位置,遞歸或迭代解法,對每個位置,重複上面的步驟,直到找到第 k 個排列。
技巧:
階乘,理解 n! 是排列數的基本構成,用這個來分割排列數組,縮小問題範圍,每次選一個數字後,把問題縮小到 n-1 個數字上,k 的更新,每次選完一個數後,用 k % (n-1)! 更新 k,就能找到剩下部分的第 k 個排列。
思路:
建一個從 1 到 n 的數字列表,用 k // (n-1)! 找到每個位置應該放哪個數字,再用更新後的 k 繼續計算下一個位置的數字,最後把這些數字拼起來,構成第 k 個排列。
程式碼:

import math

class Solution(object):
def getPermutation(self, n, k):
"""
:type n: int
:type k: int
:rtype: str
"""
#建 1 到 n 的數字列表
numbers = list(range(1, n+1))
#轉換 k 為 0-indexed
k -= 1
result = []

    #算每一層的數字
    for i in range(n, 0, -1):
        # 算階乘 (i-1)!
        fact = math.factorial(i-1)
        #決定當前位置的數字
        index = k // fact
        result.append(str(numbers[index]))
        #從數字列表裡刪已用過的數字
        numbers.pop(index)
        #更新 k 值
        k %= fact
    
    return ''.join(result)

解釋:
初始化數字列表,numbers = list(range(1, n+1)),從這個列表裡每次選擇數字,調整 k,k -= 1 是為了把 k 變成 0 索引,比較好算,用迴圈算每個位置的數字,fact = math.factorial(i-1) 算階乘,找到當前應選的數字位置 index = k // fact,把這個數字加到結果,再從 numbers 刪調那個數字,更新 k,每次用 k %= fact 更新 k,讓剩下的數字位置繼續計算。
問題:
索引錯誤,要注意 k 是從 1 開始不是 0,所以開始要對讓k 減 1。
效率:雖然用階乘來減少排列生成的數量,但如果沒有處理好數組的選擇和更新,還是會出現效率低下的情況。
這個時間複雜度是 O(n^2),因為每次選擇數字後從 numbers 刪除數字是線性操作。


上一篇
D11:Q56Merge Intervals
下一篇
D13:Q68Text Justification
系列文
Leecode刷題28
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言