Full permutation - recursive implementation + lexicographical algorithm - java

full array

Input arrays with different elements of length n, each element is arranged in a certain order, all the sequence sets formed are full arrangement, such as input [1, 2, 3], the full arrangement is: "[1, 2, 3] ,[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]”.

  • Commonly used implementation methods are recursive method and lexicographical algorithm.

1. Recursive implementation of full permutation

Given an array of n elements, the recursive process of its full arrangement can be described as follows:
1. Take any element and place it in the first position;
2. Arbitrarily combine the remaining n-1 elements, which can be regarded as Full permutation of an array of length n-1;
3. Repeat step 2 until only one element is left at the end;
4. Repeat steps 1, 2, and 3 until all elements are placed in the first position, all permutations end.

Taking the array [1, 2, 3] as an example, the process of its full arrangement is as follows:
1. Take 1 and place it in the first position, followed by the full arrangement of (2, 3);
- the full arrangement of (2, 3) Arrange, take 2 first, only 3 — [1,2,3]
- (2,3) are left, take 3 first, only 2 — [1,3, 2]
2. Take 2 and put it in the first position, followed by the full permutation of
(1,3); - For the full permutation of (1,3), take 1 and put it in the first position, leaving only 3 — [2 ,1,3]
- the full permutation of (1,3), take 3 and put it first, leaving only 1 — [2,3,1]
3. Take 3 and put it in the first position, followed by ( 1,2) full permutation;
- (1,2) full permutation, take 1 first, leaving only 2 — [3,1,2]
- (1,2) full permutation, take 2 put first, only 1 remains — [3,2,1]

public class perms{
    public static void main(String[] args){
        int[] nums = {1,2,3};
        Permutation1(nums, 0, nums.length-1);
    }
    //递归全排列函数
    public static void Permutation1(int[] nums, int low, int high){
        if(low == high){
            for(int num : nums){
                System.out.print(num + " ");
            }
            System.out.println();
        }
        //在数组nums[low,high]中,依次把把下标为low,low+1,....,high的数值放在第一位
        for(int i = low; i <= high; i++){
            // 把下标为i的数,和下标为low的数进行交换
            swap(nums, low, i);
            // 对剩下的部分继续使用递归排列
            Permutation1(nums, low+1, high);
            // 把下标为i的数和下标为low的数交换回来,用以i+1的交换
            swap(nums, low, i);
        }
    }
    private static void swap(int[] nums, int idx1, int idx2){
        int tmp = nums[idx1];
        nums[idx1] = nums[idx2];
        nums[idx2] = tmp;
    }
}

Since the problem is decomposed by recursion, it is relatively easy to understand, but it needs to consume a lot of stack space. If the function stack space is not enough, overflow will occur, and the function call overhead is large.

2. Full permutation lexicographic algorithm

The lexicographical order is a way to compare the size of the sequence formed by the elements of the set A; the comparison method is to compare the corresponding elements of the two sequences from front to back. If the corresponding elements of the current position are the same, continue to compare the next position. , until the position of the first element is different, the element with the larger element value is greater than the element with the smaller element value in the lexicographical order (the element with the larger element value comes later).

  • Taking {1,2,3,4} as an example, the resulting arrangement is 1234 < 1243, and 1234 is arranged in front of 1243

The basic process of generating full permutation in lexicographical order,
given an array A[N], the basic process of using lexicographical order to output full permutation is described as follows:
1. Sort A in increasing order of element size to form A1 with the smallest lexicographical order;
2 . From the left start from A[0] to find the last satisfaction A [ k ] < A [ k + 1 ] ( k < n 1 ) The element A[k] of , n is the number of elements;
3. Find the smallest number A[i] greater than A[k] in A[k+1,n-1], exchange A[k] and A[i ];
4. Reverse the data order between A[k+1,n-1], A[k+1] and A[n-1] are exchanged, A[k+2] and a[n-2] Swap..., so that the next arrangement A2 of A1 in the lexicographic order is obtained;
5. Repeat steps 2~4 until all elements of A are arranged in reverse order from large to small, and the whole arrangement is completed.

The lexicographical generation of full permutation is: first generate the first sequence in the lexicographical order, and then continue to generate the next sequence.

  • In practice, steps 2 and 3 can be searched from back to front to find numbers that satisfy the conditions, which can improve efficiency.

The lexicographical order uses the iterative method to avoid a large number of recursive calls to the stack and time overhead, and the time complexity of generating the next sequence is O ( n )

public class perms{
    public static void main(String[] args){
        int[] nums = {1,2,3,4};
        Permutation2(nums);
    }
    //递归全排列函数
    public static void Permutation2(int[] nums){
        //先把数组升序排列,作为字典序的第一个序列,并打印出来
        Arrays.sort(nums);
        printNums(nums);
        // 不断寻找当前序列的下一个序列
        while(true){
            //1.寻找A[k],从后向前
            int k = nums.length - 2;
            while(k >= 0 && nums[k] >= nums[k+1] ){ k--; }
            //如果k等于-1,说明整个序列都是逆序的,是字典序的最后一个序列了
            if(k == -1){ return; }
            //2.在A[k+1,n-1]中找到大于A[k]的最小数A[i],交换A[k]与A[i]
            if(k >= 0){
                int j = nums.length-1;
                while(j>= k+1 && nums[j] <= nums[k]){  j--; }
                swap(nums, k, j);
            }
            //3.反转A[k+1,n-1]之间的数据顺序
            reverse(nums, k+1);
            printNums(nums);
        }
    }
    private static void swap(int[] nums, int idx1, int idx2){
        int tmp = nums[idx1];
        nums[idx1] = nums[idx2];
        nums[idx2] = tmp;
    }
    private static void reverse(int[] nums, int idx){
        int end = nums.length-1;
        while(idx < end){
            swap(nums, idx, end);
            idx++;
            end--;
        }
    }
    private static void printNums(int[] nums){
        for(int num : nums){
            System.out.print(num + " ");
        }
        System.out.println();
    }
}

It should be noted that the sequence set obtained by the recursive method is different from the set obtained by the lexicographic method, and the former is not sorted by size.

Derivative Problems of Full Permutation Lexicographic Algorithm

A common problem derived from total sorting is: input a sequence, output its next sequence in lexicographical order ( LeetCode-31 )
code solution

  • This question can also be asked this way: given a sequence of integers, how to find the sequence of integers that is closest to it and greater than it? Let's use this case to explain the lexicographical algorithm visually.
  • Question: Given the sequence "12354", find the sequence of integers closest to and greater than it.
    1. It is known that in the lexicographical order, the sequence composed of fixed numbers, the smallest sequence is the sequence sequence "12345", and the largest sequence is the reverse sequence sequence "54321";
    2. In order to be close to the original sequence "12354", it is necessary to keep the high order unchanged as much as possible, and the low order to change the order within the smallest range, so from which digit to start the transformation? It depends on the reversed region of the current integer;
    3. The reverse order area of ​​"12354" is the last two digits of "54", which is already the maximum value, then you can only start the transformation from the previous "3", and find the smallest number greater than 3 from the reverse order area behind, and 3 Swap positions: 12354 ——> 12453;
    4. The third-to-last digit has been determined, but the last two digits are still in reverse order. We need to convert the last two digits back into order to ensure that the last two digits are as small as possible when the third-to-last digit is 4: 12453 — —> 12435;

Three steps to obtain the next sequence in lexicographical order:
1. Look at the reverse order region from the back to the front, and find the previous digit of
the reverse order region; 2. Swap the previous digit of the reverse order region with the smallest number greater than it in the reverse order region;
3. Convert the original reverse order range to order;

Guess you like

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