1. 程式人生 > >Leetcode中級演算法-全排列

Leetcode中級演算法-全排列

全排列演算法思想:

1. 全排列的定義和公式:

   從n個不同元素中任取m(m≤n)個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的一個排列。當m=n時所有的排列情況叫全排列。由排列的定義,顯然不同的順序是一個不同的排列。從n個元素中取m個元素的所有排列的個數,稱為排列數。從n個元素取出n個元素的一個排列,稱為一個全排列。

    公式:全排列數f(n) = n! (定義0!=1)

2. 時間複雜度:

   n個數(字元、物件)的全排列一共有n!種,所以全排列演算法至少時間O(n!)的。如果要對全排列進行輸出,那麼輸出的時間要O(n∗n!),因為每一個排列都有n個數據。所以實際上,全排列演算法對大型的資料是無法處理的,而一般情況下也不會要求我們去遍歷一個大型資料的全排列。

3. 全排列的初始思想

   為了解決一個演算法問題,我們選擇從基本的想法做起。先回顧一下我們自己是如何寫一組數的全排列的:1,3,5,9
首先肯定是 :

 1 ,[3, 5,9的全排列]
 3 ,[1, 5,9的全排列]
 5 ,[3, 1,9的全排列]
 9 ,[3, 5,1的全排列]     

很顯然這是一個遞迴的思路,那麼我們根據該想法寫出來的初版程式碼就是:

void permute(vector<int> &nums ,....... ){
    for (int i = 0  ; i != n  ; ++i  )
        {
            swap(nums,0
,i); //將第i個數與第一個數交換,從而得到第一個數的所有情況 1,3,5,9 resove(nums , ..... ); //其後的元素再進行全排列。 } }

給函式加上引數之後就是:

void permute(vector<int> &nums ,int p  , int q ){
    for (int i = 0  ; i != n  ; ++i  )
        {
            swap(nums,0,i); 
            resove(nums , 1, n-1
); //將後面的1~n-1 個元素再進行全排列。 } }

因為我們不一定就是從第一個元素到最後一個元素進行全排列 ,所以我們必須修改迴圈條件,使之具有普遍性:

//拿 p~q 之間的元素進行全排列
void permute(vector<int> &nums ,int p  , int q ){
    for (int i = p  ; i !=  q  ; ++i  )
        {
            swap(nums,p,i); 
            resove(nums , p+1, q ); //將後面的 p+1~q 個元素再進行全排列。
        }
    }

OK,下面才是我們的重點內容!!!動腦克啦,

  假如,我們交換到了[3,1,5,9],接下來需要由5來打頭,如果直接將5 和第一個元素交換,那麼序列就變成了[5,1,3,9] ,很顯然這是極其不正確的。所以我們還需要在由5來打頭之前,將[3,1,5,9]進行還原 。

void permute(vector<int> &nums ,int p  , int q ){
    if(p == q) {
        在這裡列印序列即可 !
    }
    for (int i = p  ; i !=  q  ; ++i  )
        {
            swap(nums,p,i); 
            resove(nums , p+1, q ); 
            swap(nums,p,i);//要還原,確保初始狀態一致。 
        }
    }

4.全排列的非去重遞迴演算法

   演算法思路:全排列可以看做固定前i位,對第i+1位之後的再進行全排列,比如固定第一位,後面跟著n-1位的全排列。那麼解決n-1位元素的全排列就能解決n位元素的全排列了,這樣的設計很容易就能用遞迴實現

題意:

給定一個沒有重複數字的序列,返回其所有可能的全排列。

示例:

輸入: [1,2,3]
輸出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

解決過程中遇到的問題:

c++ STL中怎麼定義一個二維向量(vector)

vector<型別> name(size,init_value);

vector<int> temp(num,0);//num為向量行數,0為初始化值

vector<vector<int> > test(num,TT);
//前面一個引數表示向量個數,後面引數表示是怎樣的一種向量

最後就相當於定義了一個test[num][num]的陣列

如何比較快速的求得一個數的階乘

  1. 定義暫存器變數
#include<iostream>  
using namespace std;  

int fac(int);  

int main()  
{  
    int n;  

    while(cin>>n)  
    {  
        cout<<n<<"!= "<<fac(n)<<endl;  
    }  

    return 0;  
}  

int fac(int x)  
{  
    register int i,f=1;  //定義暫存器變數  

    for(i=1;i<=x;i++)  
        f*=i;  

    return f;  
}  
  1. 利用了陣列記錄已得到的結果,並在計算下一個結果時利用了已得到的結果。
#include<iostream>  
using namespace std;  

int a[11];  

void init();  

int main()  
{  
    init();  

    int n;  

    while(cin>>n)  
    {  
        cout<<n<<"!= "<<a[n]<<endl;  
    }  

    return 0;  
}  

void init()  
{  
    int i;  

    a[0]=1;  
    for(i=1;i<=10;i++)  
        a[i]=i*a[i-1];  
}  
  1. 遞迴 (略)
  2. 使用靜態區域性變數
#include<iostream>
using namespace std;

int fac(int);

int main()
{
    int i;

    for(i=1;i<=10;i++)
    {
        cout<<i<<"!= "<<fac(i)<<endl;
    }

    return 0;
}

int fac(int x)
{
    static int f=1;   //靜態區域性變數

    f*=x;

    return f;
}

ps:推薦第二種!!!!

通過原始碼:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
using Iterator = vector<int>::iterator ;
using VV = vector<vector<int> > ;
class Solution {
public:
    void resove(VV  &intVec, vector<int> &nums , 
                Iterator be , Iterator &ed  ) {
        if (be == ed ) {
            intVec.push_back(nums);
        }
        else {
            for (auto it = be ; it != ed ; ++it )
            {
                swap(*it, *be);
                resove(intVec, nums , be + 1 , ed );
                swap(*it, *be);
            }
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        VV  intVec  ; 
        Iterator  be = nums.begin() , ed = nums.end() ;
        resove(intVec, nums , be, ed  ) ;  // 3
        return intVec ;
    }
} ;

相關推薦

Leetcode中級演算法-排列

全排列演算法思想: 1. 全排列的定義和公式:    從n個不同元素中任取m(m≤n)個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的一個排列。當m=n時所有的排列情況叫全排列。由排列的定義,顯然不同的順序是一個不同的排列。從n個元素中

leetcode題庫——排列II

題目描述: 給定一個可包含重複數字的序列,返回所有不重複的全排列。 示例: 輸入: [1,1,2] 輸出: [ [1,1,2], [1,2,1], [2,1,1] ] 方法: class Solution { public: vector<vecto

leetcode題庫——排列

題目描述: 給定一個沒有重複數字的序列,返回其所有可能的全排列。 示例: 輸入: [1,2,3] 輸出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 方法:深搜 class Solu

leetcode——中級演算法——陣列和字串——無重複字元的最長字串

給定一個字串,找出不含有重複字元的最長子串的長度。 示例1 輸入: "abcabcbb" 輸出: 3 解釋: 無重複字元的最長子串是 "abc",其長度為 3 示例2 輸入: "bbbbb" 輸出: 1 解釋: 無重複字元的最長子串是 "b",其長度為 1。 示例3

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

問題1: 給定字串1234無重複字元,求其所有排列 遞迴方式求解: def swap(num, i, j): tmp = num[i] num[i] = num[j] num[j] = tmp #num無重複數字 def fullSort(num, index)

LeetCode - Permutations(排列、康託展開 Cantor expansion)- 題目 31、46、47、60、77

31. Next Permutation 46. Permutations 47. Permutations II 60. Permutation Sequence 77. Combinations 這五道題是LeetCode上關於數列的全

LeetCode——中級演算法——樹和圖——二叉樹的鋸齒形層序遍歷(JavaScript)

給定一個二叉樹,返回其節點值的鋸齒形層次遍歷。(即先從左往右,再從右往左進行下一層遍歷,以此類推,層與層之間交替進行)。 例如: 給定二叉樹 [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回鋸

LeetCode——中級演算法——陣列和字串——三數之和

給定一個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。 注意:答案中不可以包含重複的三元組。 例如, 給定陣列 nums = [-1, 0, 1, 2, -1, -4], 滿足

leetcode--中級演算法--陣列和字串--遞增的三元子序列(JavaScript)

給定一個未排序的陣列,判斷這個陣列中是否存在長度為 3 的遞增子序列。 數學表示式如下: 如果存在這樣的 i, j, k, 且滿足 0 ≤ i < j < k ≤ n-1, 使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否則返回

leetcode-中級演算法-陣列和字串-最長迴文字串

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。 示例 1: 輸入: “babad” 輸出: “bab” 注意: "aba"也是一個有效答案。 示例 2: 輸入: “cbbd” 輸出: “bb” 思路 這道題很顯然可以用暴力求解,但時

Leetcode中級演算法之字謎分組(49)C++

給定一個字串陣列,將字母異位詞組合在一起。字母異位詞指字母相同,但排列不同的字串。 示例: 輸入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”], 輸出: [ ["ate","eat","tea"], ["nat","tan"],

Leetcode中級演算法之三數之和(15) C++

給定一個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。 注意:答案中不可以包含重複的三元組。 例如, 給定陣列 nums = [-1, 0, 1, 2, -1, -4],

Leetcode中級演算法之遞增的三元子序列C++

給定一個未排序的陣列,判斷這個陣列中是否存在長度為 3 的遞增子序列。 數學表示式如下: 如果存在這樣的 i, j, k, 且滿足 0 ≤ i < j < k ≤ n-1, 使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否則返回

Leetcode中級演算法之最長迴文子串(5)C++

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為 1000。 示例 1: 輸入: “babad” 輸出: “bab” 注意: “aba” 也是一個有效答案。 示例 2: 輸入: “cbbd” 輸出: “bb” 這道題在網上看到了許多解法,如動態規劃,

Leetcode中級演算法之無重複字元的最長子串(3)C++

給定一個字串,請你找出其中不含有重複字元的 最長子串 的長度。 示例 1: 輸入: “abcabcbb” 輸出: 3 解釋: 因為無重複字元的最長子串是 “abc”,所以其長度為 3。 示例 2: 輸入: “bbbbb” 輸出: 1 解釋: 因為無重複字元的最長子串是 “b”,所

Leetcode中級演算法之奇偶連結串列(328)C++

給定一個單鏈表,把所有的奇數節點和偶數節點分別排在一起。請注意,這裡的奇數節點和偶數節點指的是節點編號的奇偶性,而不是節點的值的奇偶性。 請嘗試使用原地演算法完成。你的演算法的空間複雜度應為 O(1),時間複雜度應為 O(nodes),nodes 為節點總數。 示例 1: 輸入:

Leetcode中級演算法之兩數相加(2)C++

給出兩個 非空 的連結串列用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式儲存的,並且它們的每個節點只能儲存 一位 數字。 如果,我們將這兩個數相加起來,則會返回一個新的連結串列來表示它們的和。 您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。 示例:

leetcode python 46. 排列(中等、陣列、回溯)

給定一個沒有重複數字的序列,返回其所有可能的全排列。 示例: 輸入: [1,2,3] 輸出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 方法一:函式呼叫 class Solution: def per

LeetCode】#47排列II(Permutations II)

【LeetCode】#47全排列II(Permutations II) 題目描述 給定一個可包含重複數字的序列,返回所有不重複的全排列。 示例 輸入: [1,1,2] 輸出: [ [1,1,2], [1,2,1], [2,1,1] ] Description Give

LeetCode——中級演算法——排序和搜尋——前K個高頻元素(JavaScript)

給定一個非空的整數陣列,返回其中出現頻率前 k 高的元素。 示例 1: 輸入: nums = [1,1,1,2,2,3], k = 2 輸出: [1,2] 示例 2: 輸入: nums = [1], k = 1 輸出: [1] 說明: 你可以假設給定的 k 總是合