演算法--全排列,去重全排列以及非遞迴實現
問題1: 給定字串1234無重複字元,求其所有排列
遞迴方式求解:
def swap(num, i, j): tmp = num[i] num[i] = num[j] num[j] = tmp #num無重複數字 def fullSort(num, index): if index==len(num)-1: print (num) return for i in range(index, len(num)): swap(num, index, i) fullSort(num, index+1) swap(num, index, i)
以1234為例,首先考慮第一位的可能,有1,2,3,4四種可能,當第一位固定時,例如為1,後面三位又是一個遞迴問題,用變數index來標識當遞迴到陣列的第幾位
當index==len(num)-1時,說明所有數字已經交換完畢,則輸出陣列即可,此時為一種排列。
當index<len(num)-1時,說明例如index=0,說明當前正在考慮第index位的取值,可以把index+1一直到len(num)-1所有數字都置換到num[index]中,然後依次求解每個遞迴問題
在每一次遞迴迴圈中,陣列的位置索引資訊 0----index----i------len-1
index表示陣列的位置索引,index取值0----len-1
當index確定某一值時,該位置的取值方式可以為i=index--len-1,依次將後面數字i交換到該位置index,遞迴求解子問題
當index==len-1,說明所有可能交換情況已經完成,可以輸出該陣列,即為一種排列方式
問題2:給定字串12234,求其所有排列字串要去重
陣列索引:
0---index---i----len-1
考慮將num[index]與num[i]交換,若在index--i-1中已經存在num[i],則num[i]不應該與num[index]交換,因為交換依次為按順序交換,i取值從index一直到i,若這中間出現過num[i],說明num[index]已經被交換過,若再次交換便會出現重複。
例如 num = [1 2 2 3 4] :
index=1 i的變化範圍從1---4,當i=2時,此時num[i]=2,而在index=0---i-1=1之間num[1]=2,說明num[1]已經出現在num[0]位置上,若num[2]再次與num[0]交換,則會出現重複排列。
因此在每次將num[i]與num[index]交換時,需要考慮 num[i]在num[index:i]中是否出現過:
def isSwap(num, index, i):
for j in range(index, i):
if num[j]==num[i]:
return False
return True
去重的排列方式如下:
#num中有重複數字
def fullSort2(num, index):
if index==len(num)-1:
print (num)
return
for i in range(index, len(num)):
#print (isSwap(num, index, i))
if isSwap(num, index, i):
swap(num, index, i)
fullSort2(num, index+1)
swap(num, index, i)
問題3:給定字串1234,求其所有排列,使用非遞迴方式
非遞迴解法:
給定一個數字字串,將其看成一個整數,若每次都尋找一個比它剛好更大的數輸出,繼續尋找比上一個更大的數字,這樣依次輸出,則可以輸出所有組合,並且不會重複。
尋找一個比某數剛好更大的方法:
給定數字字串陣列,從後往前尋找,尋找一個相鄰遞增的兩個數,則前一個數稱為替換數,其索引稱為替換點;然後從替換點之後開始尋找一個比替換數大的最小數,稱為被替換數;交換替換數以及被替換數;將替換點之後的所有數字翻轉;輸出該數字即時目標值。
例如: num=[5,4,7,8,2,0] 從後往前尋找相鄰遞增的兩個數為7,8,則替換數為7 替換點為index=2 從替換點往後尋找比替換數大的最小值,即被替換數為8,交換7,8 得548720,把替換點之後的數字給翻轉 得到548027 。即比547820大的第一個數為548027
輸出一個數組,首先進行排序獲取到最小值,然後依次執行上述過程,逐次增大該數,一直到最大值結束即可。
#尋找比替換點大的最小數,倒序尋找,第一個大的數就是目標值
def findBiggerThanReplaceNum(num, r):
min = r
for i in range(len(num)-1, r, -1):
if num[i]>num[r]:
return i
return min
def reverse(num, i, j):
while i<j:
swap(num, i, j)
i += 1
j -= 1
def fullSort3(num):
num.sort()
print (num)
#替換數的下標 排序完成後第一個數
r = len(num)-1
#替換點的下一個數座標
m = r
while r>0:
m = r
r -= 1
#print ('r = ', r)
if num[r]<num[m]:
s = findBiggerThanReplaceNum(num, r)
#print ('s = ',s)
swap(num, r, s)
reverse(num, r+1, len(num)-1)
print (num)
#break
r = len(num)-1
首先排序陣列
r表示迴圈尋找替換點變數 m表示為r下一個索引
若num[r]<num[m]則說明r為替換點,找到替換點之後比替換數大的最小值被替換數s,從後往前第一個比替換數大的數即為被替換數
交換替換數以及被替換數
翻轉替換數之後的所有字元
r指向陣列末尾len-1,繼續迴圈
當陣列已經完全降序輸出時,r從len-1一直到0,當r=0,m=1此時num[r]<num[m]仍不滿足,則退出迴圈,結束遍歷。