Recursive divide and conquer --- example 1. Full Permutation

Keywords: Algorithm leetcode Dynamic Programming

Recursive divide and Conquer - Example 1. Full Permutation

1, Problem description

A recursive algorithm is designed to generate the full arrangement of n elements {r1, r2,..., rn}
This question is related to Li Kou master station question 46 - the whole arrangement is the same , and Likou master station question 47 - full arrangement II

2, Problem solving ideas

Let R={r1,r2..., rn} be n elements to be arranged, Ri=R-{ri}. The full arrangement of elements in set X is marked as Perm(X).(ri)Perm(X) represents the arrangement obtained by adding the prefix ri before each arrangement of full arrangement X

The full permutation of R can be summarized and defined as follows:

  • When n==1, Perm ®=®, Where R is the only element in the set R
  • Perm when n > 1 ® It consists of (r1)Perm(R1),(r2)Perm(r2),..., (rn)Perm(rn)

Through the above analysis, we can clearly see that large-scale problems can be divided into small-scale problems, and the solution of the total problem can be combined from the solutions of each small problem
With this property, we can naturally relate to the idea of recursive partition

The code is as follows:

void Perm(T list[], int low, int high)
{
    if(low == high)		//Indicates that the last character has been filled in and the answer is output
    {
        for(int i=0; i<=high; ++i)
        {
            cout<<list[i];
            cout.width(4);
        }
        cout<<'\n';
    }
    for(int i=low; i<=high; ++i)  //0~low is the character that has been filled in. We select a new character in low~high to fill in, that is, list[i] and list[low] exchange positions
    {
        swap(list[i], list[low]);
        Perm(list, low+1, high);  //Continue to fill in the next character recursively, and the parameter low becomes low+1
        swap(list[i], list[low]); //After the recursion comes back, remember to exchange it back and restore it as it is
    }
}

Let's go a step further and consider what to do if there are duplicate elements in the array?

Since full permutation is to exchange each number with the number after it from the first number, let's try to add this judgment first - if a number is the same as the following number, the two numbers will not be exchanged
For example, in 122, the first number is exchanged with the following 212 and 221. Then the second number in 122 does not need to be exchanged with the third number, but for 212, its second number is different from the third number. After exchange, 221 is obtained, which is repeated with the 221 obtained by exchanging the first number and the third number in 122. Therefore, this method does not work

In other words, for 122, the first number 1 and the second number 2 are exchanged to obtain 212, and then consider the exchange of the first number 1 and the third number 2,

At this time, since the third number is equal to the second number, the first number is no longer exchanged with the third number. Considering 212, the exchange between its second number and the third number can be solved 221. At this time, the generation of the full permutation is completed

In this way, we also get the rule of removing repetition in the full arrangement - the full arrangement of removing duplication is to exchange each number from the first number with the non recurring number behind it. In programming words, when the i-th number is exchanged with the j-th number, it is required that there is no number equal to the j-th number in [i,j). That is, it is guaranteed that the number filled in each time must be in the repetition set of this number "The first unfilled number from left to right
Judge whether any number in [nBegin,nEnd] in str array is equal to the number with the subscript nEnd

The code is as follows:

#include<bits/stdc++.h>
using namespace std;
bool IsSwap(char *str, int nBegin, int nEnd)  //Ensure that the number filled in each time must be the "first unfilled number from left to right" in the repetition set of this number
{
    for(int i=nBegin; i<nEnd; i++)
        if(str[i]==str[nEnd]) return false;
    return true;
}
// k represents the number currently selected, and m represents the size of the array
void AllRange(char *str, int k, int m)
{
    if(k==m)
    {
        static int count = 1;
        string ans = "";
        for(int i=0; i<m; i++) ans += str[i];
        cout<<"The first"<<count++<<"The first arrangement is"<<ans<<endl;
    }
    else 
    {
        for(int i=k; i<m; i++)
        {
            if(IsSwap(str, k, i))  //Only the first element in the same layer is useful
            {
                swap(str[i], str[k]);
                AllRange(str, k+1, m);
                swap(str[i], str[k]);
            }
        }
    }
}
int main()
{
    // Cout < < "full arrangement without duplicate elements in the array:" < < endl;
    // int n;
    // Cout < < "please enter the array size:";
    // while(cin>>n && n!=0)
    // {
    //     Cout < < "please enter array elements:" < < endl;
    //     int *a = new int[n];
    //     for(int i=0; i<n; i++) cin>>a[i];
    //     Perm(a, 0, n);
    //     Cout < < "please enter the array size:";
    // }

    cout<<"Full array with duplicate elements in the array:"<<endl;
    int n;
    cout<<"Please enter the array size:";
    while(cin>>n && n!=0)
    {
        cout<<"Please enter an array element:"<<endl;
        char *a = new char[n];
        for(int i=0; i<n; i++)  cin>>a[i];
        AllRange(a, 0, n);
        cout<<"Please enter the array size:";
    }
    system("pause");
    return 0;
}

Operation results: (the first picture shows the full arrangement without repeated elements, and the second picture shows the full arrangement with repeated elements (the data is too fierce, and the full arrangement of 13 characters runs for a long time))

Refer to the courseware of algorithm design and analysis by Mr. Bi Fangming

Welcome to the personal blog website - George's programming cabin , work hard with me for the big factory offer!

Posted by ale_jrb on Tue, 30 Nov 2021 14:22:12 -0800