1. 程式人生 > 實用技巧 >Leedcode316去除重複字母

Leedcode316去除重複字母

今天學習並記錄一下全排列問題。即給定一組序列,得到他們各個元素可以形成的所有排列組合序列。

如:1,2,3。 得到:1,2,3; 1,3,2; 2,1,3; 2,3,1; 3,1,2; 3,2,1;

拿到問題先給出自己思考的結果

1.基於選擇的全排列演算法

演算法思想:如上例,1,2,3. 第一個位置,可以有3種結果,1或2或3。在第一個位置選定後,第二個位置就只有剩下的兩種結果。.....依次類推,最後一個位置只能填最後的一個結果。

從數學的角度上看,全排列一共有n!個結果,對應的演算法時間複雜度也需要遍歷n!種。根據這個數學的想法,我編寫了如下程式。

/**
函式名稱:全排列演算法
描述:通過選擇方法實現的全排列
引數:引數一:待排列陣列,int型陣列;引數二:陣列長度,int型;
      引數三:深度;引數四:int型陣列,用於儲存結果的臨時陣列,注意長度和待排列陣列長度一致
返回值:void
漸進時間複雜度:O(pow(n,n))
編寫人:李一帆
*
*/ void permutationByChoose(int *data,int n,int length,int *tempData){ if(n==length){ listPrint(tempData,length); cout<<endl; }else{ for(int i=0;i<length;i++){ if(data[i]!=-1){ tempData[n]=data[i]; data[i]=-1; permutationByChoose(data,n
+1,length,tempData); data[i]=tempData[n]; } } } }

在這個程式中,設定一個臨時的陣列作為排序結果的儲存。每次遞迴填好一個數,每次遞迴的廣度迴圈中,遍歷每個待排列陣列的元素,將標記為“未被使用(程式中為不為-1的元素)”,最終得到所有結果。

下來學習演算法書上的全排列演算法

2.基於交換的全排列演算法。

演算法思想:書中用到了字首的概念,但實質和數學上和我的演算法思想相同,都是依次排好每一位的數。不同的是,書中演算法是基於交換的,相比我的演算法,少了一個臨時陣列的記憶體空間。也具有了記憶性,

將我的演算法的時間複雜度為O(pow(n,n))降低到了數學的下限O(n!)。它每次通過交換使得待排列陣列的第一項得到不同結果,但它每次遞迴時,都會將陣列長度減一,這樣在每次的遞迴中,所需處理的陣列長度

就會減少,可以降低遍歷次數。最終直到剩下的陣列長度為1時,即輸出一種結果。

下面給出程式碼

/**
函式名稱:全排列演算法
描述:通過交換方法實現的全排列
引數:引數一:待排列陣列,int型陣列;引數二:起始下標,int型;引數三:結束下標,int型;
返回值:void
漸進時間複雜度:O(n!)
編寫人:李一帆
**/
void permutationBySwap(int *data,int k,int m){
    if(k==m){
        listPrint(data,4);
        cout<<endl;
    }else{
        for(int i=k;i<=m;i++){
            swapData(&data[k],&data[i]);
            permutationBySwap(data,k+1,m);
            swapData(&data[k],&data[i]);
        }
    }
}

演算法討論

1.以上兩種演算法都在具有相同元素時,最後結果都沒有做去重。

2.書上演算法比我思考的結果優越很多,直觀上是時空複雜度的降低。還有一個問題是我思考的演算法每次需要記錄元素的狀態為待使用,這就造成了一些問題和麻煩。