LeetCode题解——Permutation总结

Leetcode Permutation总结
含其中四题:Next Permutation, Permutations, Permutations II, Permutation Sequence

Next Permutation

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place, do not allocate extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

class Solution {
public:
    void nextPermutation(vector &num) {
       
    }
};
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
分析:求下一个排列,例如:
1,2,3,4,5
1,2,3,5,4
1,2,4,3,5
...
1,2,5,4,3
1,3,2,4,5
...
大致分三个步骤:
(1)从右[len-1]往左[i],找到num[i] > num[i-1],如没有,即i==0,则num为从大到小排列的数组,则此时的下一个排列,为所有元素从小到大的排列;
(2)找到[num[i], num[len-1]]闭区间中比A[i-1]大的最小数num[minIndex],交换num[minIndex]和num[i-1],注:因为肯定有num[i] > num[i-1],所以minIndex从i开始;
(3)对新的[num[i], num[len-1]],从小到大排序。
class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int j,i=nums.size()-1;
        for(j = nums.size()-2;j>=0;j--){
            if(nums[j]<nums[j+1]) break;
        }//从数组末尾开始找,找到第一个满足nums[j]<nums[j+1]的数,记录j,在j之后的数都是降序的
        if(j>=0){
            while(nums[i]<=nums[j]) i--;//从数组末尾开始找,找到第一个比nums[j]大的数,交换他两
           swap(nums[i],nums[j]);
        }
       // sort(nums.begin()+j+1,nums.end());//然后将j后面的数逆序,那么j+1———end 一直是升序的
       reverse(nums,j+1);
    }
    
    void reverse(vector<int>&nums, int k){
        int i=k,j=nums.size()-1;
        while(i<j){
            swap(nums[i],nums[j]);
            i++;j--;
        }
    }
};



---------------------------------------------------------------------------------------------------------------------------------------------

Permutations

Given a collection of numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:
[1,2,3][1,3,2][2,1,3][2,3,1][3,1,2], and [3,2,1].

class Solution {
public:
    vector > permute(vector &num) {
       
    }
};
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
方法一:利用上述写的next permutation 的程序,此时Permutation和Permutation II一样,不管数组中是否有元素重复
class Solution {
public:
   vector<vector<int>> permute(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> ans;
        ans.push_back(nums);
        while(nextPermutation(nums)){
            ans.push_back(nums);
        }
        return ans;
    }
    
     bool nextPermutation(vector<int>& nums) {
        int j,i=nums.size()-1;
        for(j = nums.size()-2;j>=0;j--){
            if(nums[j]<nums[j+1]) break;
        }//从数组末尾开始找,找到第一个满足nums[j]<nums[j+1]的数,记录j,在j之后的数都是降序的
        if(j>=0){
            while(nums[i]<=nums[j]) i--;//从数组末尾开始找,找到第一个比nums[j]大的数,交换他两
           swap(nums[i],nums[j]);
            sort(nums.begin()+j+1,nums.end());//然后将j后面的数逆序,那么j+1———end 一直是升序的
            return true;
        }
        return false;
    } //16ms



方法二:暴力搜索法,递归

class Solution{
public:
    vector<vector<int>> permute(vector<int>& nums){
        vector<vector<int>> res;
        vector<int> temp;
        permute(nums,res,temp);
        return res;
    } 
    void permute(vector<int>& nums,  vector<vector<int>>& res,vector<int>& temp){
        if(temp.size()==nums.size()){
            res.push_back(temp);
            return;
        }
        for(int i=0; i<nums.size();i++){
            if(find(temp.begin(),temp.end(),nums[i])==temp.end()){
                temp.push_back(nums[i]);
                permute(nums,res,temp);
                temp.pop_back();
            }
        }
    }
};//16ms

方法三:改进的暴力搜索法

class Solution{
public:
      vector<vector<int>> permute(vector<int>& nums){
        vector<vector<int>> res;
        permute(nums,res,0);
        return res;
    }
private: 
    void permute(vector<int>& nums, vector<vector<int>> & res, int begin){
        if(begin==nums.size()-1){
            res.push_back(nums);
            return;
        }
        for(int i = begin; i<nums.size(); i++){// each recursive get the permutations with the first number i
            swap(nums[i],nums[begin]);
            permute(nums,res,begin+1);
            swap(nums[i],nums[begin]);
        }
    }
};  //12ms


----------------------------------------------------------------------------------------------------------------------------------------------
Permutations II

Given a collection of numbers that might contain duplicates, return all possible unique permutations.

For example,
[1,1,2] have the following unique permutations:
[1,1,2][1,2,1], and [2,1,1].

class Solution {
public:
    vector > permuteUnique(vector &num) {
       
    }
};
------------------------------------------------------------------------------------------------------------------------------------------------------------------
方法一:利用上述写的next permutation 的程序,此时Permutation和Permutation II一样,不管数组中是否有元素重复
class Solution {
public:
   vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> ans;
        ans.push_back(nums);
        while(nextPermutation(nums)){
            ans.push_back(nums);
        }
        return ans;
    }
    
     bool nextPermutation(vector<int>& nums) {
        int j,i=nums.size()-1;
        for(j = nums.size()-2;j>=0;j--){
            if(nums[j]<nums[j+1]) break;
        }//从数组末尾开始找,找到第一个满足nums[j]<nums[j+1]的数,记录j,在j之后的数都是降序的
        if(j>=0){
            while(nums[i]<=nums[j]) i--;//从数组末尾开始找,找到第一个比nums[j]大的数,交换他两
           swap(nums[i],nums[j]);
            sort(nums.begin()+j+1,nums.end());//然后将j后面的数逆序,那么j+1———end 一直是升序的
            return true;
        }
        return false;
    }
}; //32ms

方法二:暴力搜索法,递归
统计词频,迭代~
class Solution {
public:
    vector > permuteUnique(vector &num) {
        vector> result;
        n = num.size();
        unordered_map count_map;
        for(int i = 0; i < num.size(); i++){
            if(count_map.find(num[i]) == count_map.end()){
                count_map[num[i]] = 1;
            }else{
                count_map[num[i]]++;
            }
        }
       
        vector path;
        dfs(result, path, count_map);
       
        return result;
    }
   
    size_t n;
   
    void dfs(vector> &result, vector &path, unordered_map count_map){
        if(path.size() == n){
            result.push_back(path);
            return;
        }
       
        for(auto it = count_map.begin(); it != count_map.end(); it++){
            int count = 0;
            for(int j = 0; j < path.size(); j++){
                if(path[j] == it->first) count++;
            }
           
            if(count < it->second){
                path.push_back(it->first);
                dfs(result, path, count_map);
                path.pop_back();
            }
           
        }  
    }
   
};
注:要从count_map的元素来迭代,因为其中无重复元素。。。num中有重复元素

方法三:改进的递归方法
class Solution {
public:
    void recursion(vector<int> nums, int begin, vector<vector<int> > &res) {
        if (begin == nums.size()-1) {
            res.push_back(nums);
            return;
        }
        for (int k = begin; k < nums.size(); k++) {
            if (begin != k && nums[begin] == nums[k]) continue;
            swap(nums[begin], nums[k]);
            recursion(nums, begin+1, res);
            //swap(nums[begin],nums[k]);
        }
    }
    vector<vector<int> > permuteUnique(vector<int> &nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int> >res;
        recursion(nums, 0, res);
        return res;
    }
}; //32ms


-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Permutation Sequence

The set [1,2,3,…,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

 

Given n and k, return the kth permutation sequence.

Note: Given n will be between 1 and 9 inclusive.

class Solution {
public:
    string getPermutation(int n, int k) {
       
    }
};
--------------------------------------------------------------------------------------------------------------------------------------------------------
方法一,利用上述写的next permutation 的程序,此时Permutation和Permutation II一样,不管数组中是否有元素重复
class Solution {
public:
    string getPermutation(int n, int k) {
        int tolNum = 1;
        string sInit = "";
       
        for(int i = 1; i <= n; i++){
            tolNum *= i;
            char tmp = '0'+i;
            sInit.insert(sInit.end(), tmp);
        }
       
        k = k % tolNum;
        if(k == 0) k = tolNum;

        while(--k){
            sInit = nextPermutation(sInit);
               //cout<<sInit<<endl;
        }
        return sInit;
    }
   
    string nextPermutation(string &ss){
        int i = ss.size() - 1;
        for(; i > 0; i--){
            if(ss[i] > ss[i-1]) break;
        }
        if(i == 0 ) {
            sort(ss.begin(), ss.end());
            return ss;
        }
       
        int minIndex = i;
        for(int j = i+1; j < ss.size(); j++){
            if(ss[j] > ss[i-1] && ss[j] < ss[minIndex]){
                minIndex = j;
            }
        }
        swap(ss[minIndex], ss[i-1]);
        sort(ss.begin() + i, ss.end());
        return ss;
    }
};

方法二:数学解法

在n!个排列中,第一位的元素总是(n-1)!一组出现的,也就说如果p = k / (n-1)!,那么排列的最开始一个元素一定是nums[p]。

假设有n个元素,第K个permutation是
a1, a2, a3, .....   ..., an
那么a1是哪一个数字呢?
那么这里,我们把a1去掉,那么剩下的permutation为
a2, a3, .... .... an, 共计n-1个元素。 n-1个元素共有(n-1)!组排列,那么这里就可以知道
设变量K1 = K
a1 = K1 / (n-1)!
同理,a2的值可以推导为
a2 = K2 / (n-2)!
K2 = K1 % (n-1)!
 .......
a(n-1) = K(n-1) / 1!
K(n-1) = K(n-2) /2!
an = K(n-1)


方法二:数学解法
在n!个排列中,第一位的元素总是(n-1)!一组出现的,也就说如果p = k / (n-1)!,那么排列的最开始一个元素一定是nums[p]。
假设有n个元素,第K个permutation是
a1, a2, a3, ..... ..., an
那么a1是哪一个数字呢?
那么这里,我们把a1去掉,那么剩下的permutation为
a2, a3, .... .... an, 共计n-1个元素。 n-1个元素共有(n-1)!组排列,那么这里就可以知道
设变量K1 = K
a1 = K1 / (n-1)!
同理,a2的值可以推导为
a2 = K2 / (n-2)!
K2 = K1 % (n-1)!
.......
a(n-1) = K(n-1) / 1!
K(n-1) = K(n-2) /2!
an = K(n-1)

string getPermutation(int n, int k) {  
        vector<int> nums(n);  
        int pCount = 1;  
        for(int i = 0 ; i < n; ++i) {  
            nums[i] = i + 1;  
            pCount *= (i + 1);  
        }  
  
        k--;  
        string res = "";  
        for(int i = 0 ; i < n; i++) {  
            pCount = pCount/(n-i);  
            int selected = k / pCount;  
            res += ('0' + nums[selected]);  
              
            for(int j = selected; j < n-i-1; j++)  
                nums[j] = nums[j+1];  
            k = k % pCount;  
        }  
        return res;  
    }  


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
最偷懒的方法:利用STL里的next_permutation函数
vector num
bool next_permutation(num.begin(), num.end())
返回值是布尔类型,同时改变num中的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值