觸類旁通 從回溯法理解直線排列的本質 Permutation_Leetcode #46 #47

小松鼠
發佈於演算法專欄 個房間
閱讀時間約 7 分鐘

這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。

用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。

幫助讀者鞏固DFS+回溯法框架這個重要的知識點


回顧 DFS+回溯法框架

白話的意思

# 列舉所有可能的情況,遞迴展開所有分支,把符合條件的分支納入解答。


演算法框架 + 虛擬碼

def backtrack( parameter ):

# 終止條件
if stop condition:
save result if needed # 有需要的話,儲存當下的狀態作為結果​
return

# 通則​
for each possible next selection # 列出所有選擇
make a selection # 做出一個選擇​
backtrack( updated patameter ) # 遞回展開下一層​
undo selection # 撤銷選擇,回到原始狀態,準備做下一個選擇​

return

直線排列 I_Permutations

目標

輸入n個相異的元素,返回這n個元素的直線排列。


演算法 DFS + 回溯法

通則

怎樣叫做直線排列?

其實就是每個元素輪流當排頭,並且依照同樣的規則遞迴展開

1當排頭,剩下的元素遞迴展開做直線排列

2當排頭,剩下的元素遞迴展開做直線排列

...

n當排頭,剩下的元素遞迴展開做直線排列


終止條件

什麼時候代表已經做完直線排列了?

當已經把所有元素都用完了,這時候這條分支的直線排列的展開已經完成,也結束了。


程式碼 DFS + 回溯法

class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:

result = []

def perm( start):

if start == len(nums):
result.append( nums.copy() )
return

for i in range(start, len(nums) ):
nums[start], nums[i] = nums[i], nums[start]
perm(start+1)
nums[start], nums[i] = nums[i], nums[start]
return

#========================
perm( start = 0 )
return result

直線排列 II_Permutations

目標

輸入n個的元素,裡面可能有重複元素,返回這n個元素的直線排列。


演算法 DFS + 回溯法 + 集合排除重複

通則和終止條件其實和前一題相同,這邊不重複敘述。


關鍵在於,如何保證不會重複製造相同的直線排列?

有一個直覺的想法,什麼資料結構可以記錄看過的資訊,用來去除重複?

就是Set集合,把看過的元素存到集合裡面,之後遇到同樣的元素就直接跳過即可。


程式碼 DFS + 回溯法 + 集合排除重複

class Solution:

def permuteUnique(self, nums: List[int]) -> List[List[int]]:

def perm(start):

## Base case aka stop condition
if start == len(nums):
result.append(nums.copy())
return

# Avoid repetition
seen = set()

## General cases
for i in range(start, len(nums)):
if nums[i] not in seen:
seen.add(nums[i])

nums[start], nums[i] = nums[i], nums[start]
perm(start+1 )
nums[start], nums[i] = nums[i], nums[start]
return
#-----------------------------------------
result = []
perm( start = 0)
return result

另解,用字典去排除重複

字典來記錄每個元素的出現次數字典的鍵值本身就具有排除重複的性質
排列過程中,每排一次,當下數字的出現次數就減一,排到出現次數用完為止。


程式碼 DFS + 回溯法 + 字典排除重複

class Solution:

def permuteUnique(self, nums: List[int]) -> List[List[int]]:

def perm(start, cur):

## Base case aka stop condition
if start == len(nums):
result.append( cur )
return

## General cases
for number in occurrence:

# Avoid repetition
if occurrence[ number ] > 0:
occurrence[ number ] -= 1
perm(start+1, cur + [ number ] )
occurrence[ number ] += 1
return
#-----------------------------------------
occurrence = Counter(nums)
result = []
perm( start = 0, cur = [])
return result

結語

好,今天一口氣介紹了最精華的部分,

通用的DFS+回溯法的枚舉框架,還有相關的直線排列衍伸變化題與演算法建造,


希望能幫助讀者、觀眾徹底理解它的原理,鞏固知識點。

並且能夠舉一反三,洞察其背後的本質和了解相關的應用領域!


感謝收看囉! 我們下篇文章再見~

52會員
339內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
發表第一個留言支持創作者!
你可能也想看
《親子相處,人類圖9大中心系列》意志力中心瞭解父母的意志力中心如何影響孩子,以及如何引導填滿的意志力中心,與空白的意志力中心,這對於親子關係將有深遠的影響。
Thumbnail
avatar
知之
2024-01-16
《愈平靜愈有生產力》:多接觸類比世界,讓平靜成為一切生活的力量當時看到這本書介紹的內容,讓我心生興趣,好奇著最愛研究生產力的作者克里斯.貝利(Chris Bailey),竟然也會遇到瓶頸,他是如何從中面對幾乎是現代一般人的所容易發生的過勞與焦慮,從平靜中體會到生產力的力量,而這不正是我所需要的嗎? 於
Thumbnail
avatar
丁宣的幸福閱讀館
2023-07-03
讓相處不累...遠離「多心人」在職場上或家庭中,難免遇上「多心人」,你會發現跟這種人相處特別的累。 我在職場就曾碰到這樣多心的長官,在家庭裡也有這種多心的親戚;表面上客氣萬分,私下卻是踢你一腳、捅你一刀。最擅長就是「把你說過的話加油添醋、還要加工扭曲」,他這麼做,可能要孤立你,也可能要對付你。
Thumbnail
avatar
大女人的世界
2022-01-08
觸類旁通: 理解此類一事物的知識或原理, 進而推知其他同類的事理。觸類旁通: 理解此類一事物的知識或原理, 進而推知其他同類的事理。 #萌典 #轉貼
avatar
現在佛
2021-08-23
059兄弟爭雁 出處:《賢類編》  昔1人有睹2雁翔3者,將援4弓射之,曰:「獲則烹5。」其弟爭曰:「舒雁6烹宜,翔雁7燔8宜。」竟鬥而訟9於社伯10。社伯請剖雁,烹、燔半焉。已而索11雁,則凌12空遠矣。     注釋:    1.昔:從前。 2.睹:看見。 3.翔:飛翔。 4.援:拉。 5.烹:燒煮。 6.舒雁:行動遲緩的鵝。
avatar
安咕醬
2021-07-16
觸類旁通? 004呀!原來"奶娘"是這樣來的呀?
avatar
BIO-HAO
2020-09-13
觸類旁通? 003好想有個政治觀測站,讓政客/政黨的表現化為種種參數,可以被量化而被選民多個理智評估的機會。
avatar
BIO-HAO
2020-09-06
觸類旁通? 002很多手在拔樹上的葉子
avatar
BIO-HAO
2020-08-21
觸類旁通? 001自成邏輯的鬼扯~~
avatar
BIO-HAO
2020-08-05