1. 程式人生 > >演算法--全排列,去重全排列以及非遞迴實現

演算法--全排列,去重全排列以及非遞迴實現

問題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]仍不滿足,則退出迴圈,結束遍歷。