iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0

https://ithelp.ithome.com.tw/upload/images/20240924/20169309IAL7ym5yN3.png
這題要生成一個數組的所有可能排列,且每個數字都是唯一的,生成排列問題通常涉及遞迴或迭代的方法生成所有可能的數組順序,典型的回溯問題,適合用來處理排列組合。
題目要做什麼?
給一個由不同整數組成的數組 nums,我要返回該數組所有可能的排列,結果可以是任意順序的排列列表。
想法:
先理解排列的概念,排列跟組合不同,它要考慮元素的順序,對長度為 n 的數組,共有 n! 種不同的排列,我要產生這些排列,回溯法的思路,回溯法是一種試所有可能解的算法,通常會透過遞迴來實現,對於這題,可以用遞迴選擇一個數字當成當前排列的一部分,然後在剩下的數字裡繼續遞迴生成排列,直到完成一個完整的排列。
作法:
一開始從空排列開始,然後每次選ㄧ個數字加入當前排列,當排列中的數字達到 nums 的長度,表一個完整的排列生成了,就可以把它加入結果集裡,遞迴過程,會把選過的數字標記成已選,防止重複用。
技巧:
用 遞迴函數 來回溯,用一個 布爾數組 或其他方式來標記哪些數已經被選過,如果排列的長度等於 nums 的長度,把該排列加入結果。
困難:
理解回溯法的思路和怎麼實現,管理好遞迴中的狀態變化,確保已選數字的狀態能正確恢復。
步驟:
初始化一個空列表,用來存結果,定義一個遞迴函數,參數包括當前已生成的部分排列和剩下還沒用的數字,一旦部分排列達到 nums 長度時,就把它加入結果,對每個剩下的數字,遞迴生成新的排列,然後在完成當前遞迴後開始「回溯」,撤銷選擇。
要考慮怎樣把每個數字加入排列,再遞迴處理剩下的數字,回溯,遞迴一結束,就要回退,把當前選的數字從排列中移除,進入下一個選擇,重點是控制遞迴結束的條件,排列長度達到原始數組的長度時,就表示一個完整排列已經生成,這題適合用回溯法去解決,可以更有效地遍歷所有排列,且能保證結果的唯一。
回溯法的解法:
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
def backtrack(path, remaining):
# 如果路徑長度等於數組長度,表示生成一個完整排列
if not remaining:
result.append(path)
return

        #遍歷剩下的數字
        for i in range(len(remaining)):
            # 遞迴生成新排列,把當前選的數字加入路徑
            backtrack(path + [remaining[i]], remaining[:i] + remaining[i+1:])
    
    result = []
    backtrack([], nums)
    return result

解法步驟解釋:
初始化結果列表:
result = [] 用來存最終所有的排列結果。
定義遞迴函數 backtrack:
path: 當前已經生成的部分排列。
remaining: 還未沒用過的數字。
回溯結束條件:
當 remaining 數組為空,表當前的 path 已經是一個完整的排列,把它加入 result 中。
遞迴生成排列:
對剩下的數字遍歷,每次選一個數字加到當前的 path,再把那個數字從 remaining 中移除,然後遞迴跳下一步。
remaining[:i] + remaining[i+1:] 的目的是排除當前選中的數字,剩下的數字繼續遞迴。
最後返回結果:
如果所有的排列都生成,函數返回存有所有排列的 result。
例子:
輸入: nums = [1, 2, 3]
輸出: [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
時間複雜度跟空間複雜度:
時間複雜度: O(n!),因為每次選一個數字,有 n! 種不同的排列組合。
空間複雜度: O(n!),儲存所有的排列結果。
通過回溯法有效地生成了所有的排列組合,而且能保持清晰易懂的邏輯。


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

尚未有邦友留言

立即登入留言