Summary of permutation algorithms (next permutation, full permutation, Kth permutation)

One, the next arrangement

    First, STL provides two algorithms for calculating permutation and combination relationships, namely next_permutation and prev_permutation.

    next_permutation(nums.begin(),nums.end());//Next permutation

    prev_permutation(nums.begin(),nums.end())//Previous arrangement

    When it returns 1, it means that the next full permutation is found; when it returns 0, it means there is no next full permutation

1.1 The next permutation algorithm process

(1) From right to left, find the first partition number that violates the increasing trend; for example, 6 in the figure below.

(2) From right to left, find the first change number larger than the number of partitions; for example, 7 in the figure below.

(3) Swap the number of partitions and the number of changes; for example, 6 and 7 in the figure below are swapped.

(4) Reverse all numbers to the right of the partition number index. For example, the elements after 7 in the figure below.

1.2 Algorithm process in STL source code analysis

(1) First, start from the end to find two adjacent elements, let the first element be *i, the second element be *ii, and satisfy *i<*ii.

(2) After finding such a group of adjacent elements, check forward from the end to find the first element greater than *i, let it be *j, and swap the i and j elements (swap).

(3) Reverse all elements after ii.

1.3 Version 1 implementation details (C pointer implementation)

template<calss BidrectionalIterator>
bool next_permutation(BidrectionalIterator first,BidrectionalIterator last)
{
    if (first == last) return  false ; /* empty interval */ 
    BidrectionalIterator i = first;
     ++ i;
     if (i == last) return  false ;   /* only one element */
    i = last;                     /* i points to the end */   
    -- i;
     for (;;)
    {
        BidrectionalIterator ii = i;
         -- i;
         /* The above locks a group (two) of adjacent elements */ 
        if (*i < *ii)            /* If the previous element is less than the next element */
        {
            BidrectionalIterator j = last; /* Let j point to the end */ 
            while (!(*i < *--j));      /* Search forward from the end until an element larger than *i is encountered */ 
            iter_swap( i,j);           /* Swap i,j */ 
            reverse(ii,last);         /* Reverse all elements after ii */ 
            return  true ;
        }
        if (i == first)        /* Go to the front */
        {
            reverse(first,last);     /* reverse all in reverse order */ 
            return  false ;
        }
    }
}

 1.4 Version 2 implementation details (pure STL specification)

1 template<typename BidiIt>
  2  bool next_permutation(BidiIt first,BidiIt last)
  3 {
  4        const auto rfirst=reverse_iterator<BidiIt> (last);+++
  5        const auto rlast=reverse_iterator<BidiIt> (first);
  6  
 7        auto pivot= next(rfirst);
  8  
 9        while ( pivot!= rlast && *pivot >= * prev(pivot))
 10               ++pivot; // until the first number of partitions that violates the increasing trend is found, at this point, pivot points to the number of partitions; 
11  
12        if (pivot == rlast)
 13       {
 14              reverse(rfirst,rlast); // If this sequence is a descending sequence, the next sort is to reverse the entire sequence; 
15               return  false ;
 16       }
 17  
18        auto change=find_if(rfirst,rlast,bindlst(less< int >() ,*pivot)); // From right to left, find the first number greater than the number of partitions and assign it to change; 
19  
20        swep(*change,*pivot); // Swap the number of partitions and the number of changes; 
21  
22        reverse(rfirst,pivot); // Reverse the sequence after the number of partitions; 
23  
24        return  true ;      
 25 }

 1.5 The previous permutation (prev_permutation)

    Similar to next_permutation, the STL also provides a version:

 1 int prev_permutation(int *begin, int *end)
 2 {
 3     int *i=begin, *j, *k;
 4     if (i==end || ++i==end) return 0;   // 0 or 1 element, no prev permutation
 5     for (i=end-1; i!=begin;) {
 6         j = i--;    // find last decreasing pair (i,j)
 7         if (!(*i > *j)) continue;
 8         // find last k which less than i,
 9         for (k=end; !(*i > *(--k)););
10         iter_swap(i,k);
11         // now the range [j,end) is in ascending order
12         reverse(j,end);
13         return 1;
14     }
15     // current is in ascending order
16     reverse(begin,end);
17     return 0;
18 }

 

Second, the full arrangement

1.1 Use next_permutation to find the full permutation

    Find the next permutation of the initial sequence until there is no next sequence.

    For example, suppose there is a sequence {0,1,2,3,4}, the following figure is to apply the above algorithm to obtain the "next" permutation and combination step by step. In the figure, only the adjacent two elements that meet "one element is *i, the second element is *ii, and satisfy *i<*ii" are framed, and operations such as finding appropriate j, swapping, and reversing are not shown. .

code show as below:

    vector<vector<int>> permute(vector<int>& nums) {
        vector<int>temp;
        vector<vector<int>>result;
        sort(nums.begin(),nums.end());
        do
        {
            temp.clear();
            for(int i=0;i<nums.size();i++)
                temp.push_back(nums[i]);
            result.push_back(temp);
        } while (next_permutation(nums.begin(),nums.end())); // a do while loop is best because the initial sequence must be printed first 
        return result;
    }

 

1.2 Use depth-first search (DFS) to solve, to be updated later.

Third, the Kth permutation

Simple, you can use the brute force enumeration method to call next_permutation() k-1 times (note that it must be k-1 times)

code show as below:

1     string getPermutation(int n, int k) {
2         string str(n,'0');
3         for(int i=0;i<n;i++)
4             str[i]+=i+1;
5         for(int i=0;i<k-1;i++)
6             next_permutation(str.begin(),str.end());
7         return str;
8     }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324870955&siteId=291194637