permutation 系列

关于permutation的讲解,请参见http://blog.csdn.net/xuqingict/article/details/24840183

[updated 2014.7.30]

所有的Permutation无论是否有重复元素,直接使用下面的代码即可,

bool helper(vector &num)
{
    if(num.empty()) return false;
    typedef vector::iterator iter;
    iter first=num.begin(), last=num.end();
    --last;
    if(first==last) return false;
    while(last != first && !(*(last-1) < *last))--last;  //此处直接使用!< 即可。。。
    if(last==first) return false;
    iter left=last-1,right=last;
    last=num.end();
    --last;
    while(!(*left < *last))--last;   //同上!!!
    iter_swap(left,last);
    reverse(right,num.end());
    return true;
}
public:
    vector > permuteUnique(vector &num) {
        if(num.empty()) return vector >();
        vector > ret;
        sort(num.begin(), num.end());
        do
        {
            ret.push_back(num);
        }while(helper(num));
        return ret;
    }


下列题目的讲解均是基于上面的文章:


题1: 

Next Permutation

  Total Accepted: 8066  Total Submissions: 32493 My Submissions

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


给定一个permutation,直接求出下一个:

class Solution {
public:
    void nextPermutation(vector &num) {
        typedef vector::iterator iter;
        iter beg = num.begin(), end = num.end();
        if( beg == end || beg + 1 == end)return;
        
        iter right = end;
        --right;
        for(;;)
        {
            iter left = right;
            --left;
            
            if(*left < *right)
            {
                iter k = end;
                while(!(*left < *--k)){}
                iter_swap(left, k);
                reverse(right,end);
                return;
            }
            --right;
            if(right == beg)
            {
                reverse(beg, end);
                return;
            }
        }
    }
};

题2:

Permutations

  Total Accepted: 12960  Total Submissions: 42049 My Submissions

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].

返回 所有的permutation


class Solution {
private:
typedef vector::iterator iter;
bool helper(iter first, iter last)
{
    if(first == last) return false;

    if(first + 1 == last) return false;

    iter j = last;
    --j;

    while(1)
    {
        iter i = j;
        --i;
        //find a[i] < a[j] and they are adjacent
        if(*i < *j)
        {
            iter k = last;
            while(!(*i < *--k)){}
            std::swap(*i,*k);
            std::reverse(j,last);
            return true;
        }
        --j;
        //no such a[i] < a[i+1] pair found
        if( j == first)
        {
            //restore the first of the permutation
            std::reverse(first, last);
            return false;
        }
    }
    
}
public:
    vector > permute(vector &num) {
        vector > ret;
        if(num.empty())return ret;

        iter beg = num.begin(), end = num.end();
        
        if(beg + 1 == end)
        {
            ret.push_back(num);
            return ret;
        }
        sort(beg,end); //首先必须sort!!!!
        
        do{
            ret.push_back(num);
        }while(helper(beg, end));
        
        return ret;
    }
};



题3:

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].

有重复元素的permutation,使用set结构来存储结果即可:

class Solution {
private:
typedef vector::iterator iter;
bool permutation(iter beg, iter end)
{
    if(beg == end || beg + 1 == end)
    {
        return false;
    }
    iter right = end;
    --right;
    while(1)
    {
        iter left = right;
        --left;
        if(*left < *right)
        {
            iter k = end;
            while(!(*left < *--k)){}
            iter_swap(left,k);
            reverse(right,end);
            return true;
        }
        --right;
        if(right == beg)
        {
            reverse(beg,end);
            return false;
        }
    }
}

public:
    vector > permuteUnique(vector &num) {
        set > unique;
        sort(num.begin(), num.end());
        
        do
        {
            if(unique.count(num) == 0 )
                unique.insert(num);
        }while(permutation(num.begin(),num.end()));
        
        vector > ret(unique.begin(), unique.end());
        
        /*for(set >::iterator it = unique.begin();
        it != unique.end() ; ++it)
        {
            ret.push_back(*it);
        }*/
        
        return ret;
    }
};

题4 : 给出第k-th个permutation:

Permutation Sequence

  Total Accepted: 6704  Total Submissions: 31386 My Submissions

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.


解题思路:

首先,假设  n = 3, k = 4 , 我们可以得到上述的编码,可以发现,前 (n-1)!个元素是以  1  开头的,,第二组 (n-1)!的元素是以2开头的,那么我们就可以有

 k = 4 = 2*2! + 0* 1! + 0*0!,那么该串中的字符应该是第2个,第0个,以及第0个字符,这里请注意,每一步的原始的元素集合是在减少1 的,比如;

第2个意味着 “123”的第2个,为‘3’, 那么此时的串变为 “12”

第0个意味着 “12”的第0个, 为 ‘1’,那么此时的串变为 “2”

第0个意味着 “2”的第0个,为 ‘2’, 那么此时串为空,结束,那么结果即为 “312”。

但是我们发现现在求的 “312”实际上是第5个(因为结果是从1开始的),因此只需要在计算之前将 k减一即可。也就是说在k之前一共有  k-1 个permutation,因此代码为:


class Solution {
public:
    string getPermutation(int n, int k) 
    {
        string str;
        for(int i = 1 ; i <= n ; ++i)
            str += ('0' + i);
            
        string ret;
        
        int base = 1;
        for(int i = n-1 ; i >= 1 ; --i)
        {
            base *= i;
        }
        
        
        --k;
        int i = n-1;
        while(i > 0 && k > 0) // iterate (n-1) times
        {
            int pos = k/base;
            k = k % base;
            ret += str[pos];
            str.erase(pos,1);
            base /= i;
            --i;
        }
        //[updated] 可以直接写成if(!str.empty()) ret+=str;
        while(!str.empty())
        {
            ret += str[0];
            str.erase(0,1);
            --i;
        }
        return ret;
            
    }
};

上述permutation的题目,比较函数默认为less,如果为greater是同样的道理。


你可能感兴趣的:(算法)