leetcode 46. 全排列


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

示例:

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

思路:遞歸的思路來實現,即固定第一位,對剩下的數字進行同樣的算法,知道把一個數組全部遍歷完。
用vector<vector<int>>& ans來保存全排列的數組, 用begin來表示需要全排列的起始位置,end來表示需要全排列的終止位置
很明顯可以看出這種算法的復雜度為O(n!),第一位需要交換n次, 第二位需要交換n-1次,....
上面說的固定,其實就是遞歸的交換第i位
可以發現程序中有兩個swap(nums, begin, i)的調用,首先這是交換nums中的begin,i之間的數字。 再者調用兩次是把數組還原,以便保證下一個排列的正確性
用1,2,3來解釋這個程序,最開始的時候begin=0, end = 2;(end始終是數組的最后一位的下標)
permute(nums, ans, 0, 2)
  i=0;  //交換第一位
  swap(nums,0,0);                   nums=1,2,3
  permute(nums, ans, 1, 2)
    i=1;
    swap(nums, 1, 1);                   nums=1,2,3
    permute(nums, ans, 2, 2)
      ans.push(nums);              ans=[[1,2,3]]
    //完成一個完整的排列后,把數組還原到上一個狀態,這個完整的排列是針對遞歸中的每一個子列而言的,而不是對整個數列而言的
    swap(nums, 1, 2);                   nums=1,2,3
    i=2;
    swap(nums, 1, 2);                   nums=1,3,2
    permute(nums, ans, 2, 2)
      ans.push(nums);                  ans=[[1,2,3],[1,3,2]]
    swap(nums, 1, 2);                   nums=1,2,3
  swap(nums, 0, 0)                      nums=1,2,3
  i=1;
  swap(nums, 0, 1);                     nums=2,1,3
  permute(nums, ans, 1, 2);
    i=1;
    swap(nums, 1, 1);                   nums = 2,1,3
    permute(nums, ans, 2, 2);
      ans.push_back(nums);               ans=[[1,2,3], [1,3,2], [2,1,3]]
    swap(nums, 1, 1);                   nums = 2,1,3
    i=2;
    swap(nums, 1, 2);                   nums=2,3,1
    permute(nums, ans, 2, 2);
      ans.push_back(nums);               ans=[[1,2,3], [1,3,2], [2,1,3], [2,3,1]]
    swap(nums, 1, 2);                    nums=2,1,3
  swap(nums, 0, 1);                    nums=1,2,3
  i=2;
  swap(nums, 0, 2);                      nums=3,2,1
  permute(nums, ans, 1, 2);
    i = 1;
    swap(nums, 1, 1);                    nums=3,2,1
    permute(nums, ans, 2, 2);
      ans.push_back(nums);               ans=[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,2,1]]
    swap(nums, 1, 1);                   nums=3,2,1
    i = 2;
    swap(nums, 1, 2);                  nums=3,1,2
    permute(nums, ans, 2, 2);
      ans.push_back(nums);               ans=[[1,2,3],[1,3,2],[2,1,3],[3,2,1],[3,1,2]]
    swap(nums, 1, 2);                   nums=3,2,1
  swap(nums, 0, 2);                      nums=1,2,3
  
結合上面的遞歸分析和下面的程序就很容易理解這個遞歸的算法
 1 class Solution {
 2 public:
 3     void permute(vector<int>&nums, vector<vector<int>>& ans, int begin, int end){
 4         if(begin == end){//完成一次完整的排列,就把此時的nums壓入到ans中
 5             ans.push_back(nums);
 6             return;
 7         }else{
 8             for(int i = begin; i <= end; i++){
 9                 swap(nums, begin, i);  
10                 permute(nums, ans, begin+1, end);//對剩下的元素進行全排列
11                 swap(nums, begin, i);  //還原數組
12             }
13         }
14     }
15     
16     void swap(vector<int>& nums, int k, int i){
17         int temp = nums[k];
18         nums[k] = nums[i];
19         nums[i] = temp;
20     }
21     
22     vector<vector<int>> permute(vector<int>& nums) {
23         vector<vector<int>> ans;
24         int len = nums.size()-1;
25         permute(nums, ans, 0, len);
26         return ans;
27     }
28 };

 

nums按值傳遞,會讓代碼更加簡便,按值傳遞不會改變nums原來的排列,因而不需要多余的一次swap來使其恢復原來的排列。

 1 class Solution {
 2 public:
 3     void permute(vector<int>nums, vector<vector<int>>& ans, int begin, int end){
 4         if(begin > end){
 5             ans.push_back(nums);
 6             return;
 7         }else{
 8             for(int i = begin; i <= end; i++){
 9                 swap(nums[begin], nums[i]);
10                 permute(nums, ans, begin+1, end); 
11             }
12         }
13     }
14     
15   
16     
17     vector<vector<int>> permute(vector<int>& nums) {
18         vector<vector<int>> ans;
19         int len = nums.size()-1;
20         permute(nums, ans, 0, len);
21         return ans;
22     }
23 };

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM