1. 程式人生 > >【python資料結構與演算法】【劍指offer】字串的排列

【python資料結構與演算法】【劍指offer】字串的排列

題目描述:

輸入一個字串,按字典序打印出該字串中字元的所有排列。例如輸入字串abc,則打印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba,且要求輸出字串按序排列,不可重複

 

思路:

其實排列問題的思路很簡單,有點類似《劍指offer》裡那道“青蛙跳臺階”的題目,即——對於字串長度為n的情況,將第一位的情況固定後,剩下的就是(n-1)長度字串的情況,也就可以使用遞迴呼叫了。

所以很容易想到迴圈遍歷,將遍歷到的每個不同的字元放在第一個,然後對刪去這個字元的剩餘子串進行再次遍歷,然後再確定第二個位置的字元,以此類推。最終在字串被全部確定位置之後,輸出“,”作為結束。

因此我們很容易寫出以下的程式碼:

def Permutation(ss):
    if not ss:
        print(',',end='')
    else:
        for i in ss:
            print(i,end='')
            Permutation(ss.replace(i,'',1))   # 刪掉該字串中的第一個"i"字元.注意,後面的1不可省略


Permutation('abc')
>>> abc,cb,bac,ca,cab,ba,

容易看到也容易分析出,有三個字串漏掉了首字母。這是為什麼呢?假設我們首字母是“a”,在遞迴呼叫Permutation()時,新的字串ss='bc'(a被刪掉了),則新一輪的for迴圈會迴圈到b和c。迴圈到b的時候,後面繼續遞迴呼叫輸出“c”和“,”,最終輸出的就是“abc,

”;迴圈到c的時候,後面繼續遞迴呼叫輸出“b”和“,”,但由於一開始的“a”已經在前面的字串裡了,所有這輪迴圈其實是沒輸出“a”的,所以輸出結果就是“cb,”。

所以我們應該將每次迴圈得到的字元立馬新增到字串中去,如首字元若確定為“a”,則立馬將“a”加入字串首個位置,讓後面遍歷確定的其他字元新增到含有“a”的這個字串後面。因而我們需要一個空字元串來依次記錄加入的字元;

此外,由於最後我們要求輸出一個有序的排列,所以我們還涉及到對不同字串的排序,所以我們還需要一個空list,用於存放每一個排列完畢的字串。

最後,這個空字串和空list必須要在遞迴呼叫之外,否則每次遞迴呼叫都會清空字串和list,前面的努力就白費了。因此,我們得在Solution類中在定義一個專門用於遞迴的函式,我姑且稱之為per()。

分析完畢,程式碼見下:

class Solution:
    def Permutation(self, ss):
        if not ss:
            return []
        res = set(self.per([],ss,''))    # 使用set是為了剔除因字元重複而輸出的完全一樣的排列
        return sorted(res)         

    def per(self,temp,temp_ss,path):     # temp:臨時空list;temp_ss:臨時空字串。
        if not temp_ss:
            temp.append(path)
        else:
            for i in temp_ss:
                self.per(temp,temp_ss.replace(i,'',1),path+i)   # replace方法最後的“1”的存在的意義,是防止當字串中存在重複字元時,以下刪了不止一個字元
        return temp

最後說說sort()和sorted()的區別——

  • sort 是應用在 list 上的方法,sorted 可以對所有可迭代的物件進行排序操作。
  • list 的 sort 方法返回的是對已經存在的列表進行操作,無返回值,而內建函式 sorted 方法返回的是一個新的 list,而不是在原來的基礎上進行的操作。