アルゴリズム設計と分析:2-9配列の辞書順問題


2-9の辞書順の問題
問題の説明
n個の要素{1,2,...,n}はn!個の異なる配列.これをn!個の配列を辞書順に並べ、0,1,...,n!-1.各配列の番号は、辞書の順序値です.例えば、n=3の場合、6つの異なる配列の辞書シーケンス値は以下のようになる.
ディクショナリ順序値
0
1
2
3
4
5
整列
123
132
213
231
312
321
n,およびn個の要素{1,2,...,n}の配列を与え,この配列の辞書順値と辞書順に配列された次の配列を計算した.
ぜんはいち
Java: version-1
import java.util.*;

public class Main {

    private static int n;
    private static String inputStr;
    private static char[] strToChar = new char[1000];

    private static String tmpPerm;

    private static Set permSet = new HashSet<>();

    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);

        while(true){
            permSet.clear();

            System.out.println("Please input the length of string: ");
            n = input.nextInt();
            System.out.println("Please input a digit string: ");
            inputStr = input.next();
            System.out.println("-------------------------");
            strToChar = inputStr.toCharArray();

            permutate(strToChar, 0, n-1);

            int i=0;
            int size = permSet.size();
            String[] numbers = new String[size];
            Iterator iterator = permSet.iterator();
            while (iterator.hasNext()){
                String value = iterator.next();
                numbers[i++] = value;
            }

            Arrays.sort(numbers);
            for(i=0; iif(numbers[i].equals(inputStr)) {
                    System.out.println("Permutation at: "+i);
                    if(i+1 < size)
                        System.out.println("Next permutation: "+numbers[i+1]);
                    else
                        System.out.println("There is no permutation after: "+numbers[i]);
                }
            }

            System.out.println("------------------------------------------");
        }
    }

    private static void permutate(char[] charList, int k, int m){
        if(k == m){
            tmpPerm = String.valueOf(charList);
            permSet.add(tmpPerm);
            return;
        }

        for(int i=k; i<=m; i++){
            swap(charList, k, i);
            permutate(charList, k+1, m);
            swap(charList, k, i);
        }
    }

    private static void swap(char[] charList, int k, int i){
        char temp;
        temp = charList[k];
        charList[k] = charList[i];
        charList[i] = temp;
    }
}

Input & Output
Please input the length of string: 
8
Please input a digit string: 
26458173
-------------------------
Permutation at: 8227
Next permutation: 26458317
------------------------------------------
Please input the length of string: 
8
Please input a digit string: 
87654321
-------------------------
Permutation at: 40319
There is no permutation after: 87654321
------------------------------------------
Please input the length of string: 
8
Please input a digit string: 
87654312
-------------------------
Permutation at: 40318
Next permutation: 87654321
------------------------------------------
Please input the length of string: 
6
Please input a digit string: 
231456
-------------------------
Permutation at: 144
Next permutation: 231465
------------------------------------------
Please input the length of string: 

数学的導出
Java: version-2
import java.util.Scanner;

public class Main{

    private static boolean hasNextPerm = true;

    public static void main(String[] args){

        int n;

        Scanner input = new Scanner(System.in);

        while(true){

            System.out.println("Input the number of digits:");
            n = input.nextInt();

            int[] numbers = new int[n];

            System.out.println("Input digits:");
            for(int i=0; iint rank = dictRank(numbers, n);

            nextPermutation(numbers, n);

            System.out.println("Permutation at: "+rank);

            if(hasNextPerm) {
                System.out.print("Next Permutation: ");
            }
            else
                System.out.print("There is no permutation after: ");

            for (int i = 0; i < n; i++)
                System.out.print(numbers[i]);

            System.out.println();
            System.out.println("-------------------------------------");
        }

    }

    /*
        2 6 4 5 8 1 7 3      ?
    1          P(i-1) < P(i)   
            2 6 4 4 5 8 1 
    //     
    private static void nextPermutation(int[] numbers, int n){
        int min=0, max=n-1, i, j;
        for(i=n-1; i>0; i--){ //1
            if(numbers[i-1] < numbers[i]){
                min = i-1;
                break;
            }
        }
        if(i == 0)
            hasNextPerm = false;
        else{

            hasNextPerm = true;
            for(j=n-1; j>=0; j--){ //2
                if(numbers[j] > numbers[min]){
                    max = j;
                    break;
                }
            }

            swap(numbers, min, max); //3

            reverse(numbers, min+1, n-1); //4
        }
    }

    //  
    private static void reverse(int[] numbers, int from, int to){
        int[] tmp = new int[to+1];
        for(int h=from; h<=to; h++)
            tmp[h] = numbers[h];

        for(int h=from; h<=to; h++)
            numbers[h] = tmp[to+from-h];
    }

    //  
    private static void swap(int[] numbers, int min, int max){
        int tmp = numbers[min];
        numbers[min] = numbers[max];
        numbers[max] = tmp;
    }

    /*
    2 6 4 5 8 1 7 3
    total=0;
     2    1 ,  total+=1*7!;
     6    4 ,  total+=4*6!;
     4    2 ,  total+=2*5!;
     5    2 ,  total+=2*4!;
     8    3 ,  total+=3*3!;
     1    0 ,  total+=0*2!;
     7    1 ,  total+=1*1!;
     3     ;
    */
    //        
    private static int dictRank(int[] numbers, int n){
        int count;
        int total = 0;
        for(int i=0; i1; i++){
            count = 0;
            for(int j=i+1; jif(numbers[j] < numbers[i])
                    count++;
            total += count*factorial(n-i-1);
        }

        return total;
    }

    //        
    private static int dictRank2(int[] numbers, int n){
        int count;
        int sum = 0;

        for(int i=0; i1; i++){
            count = numbers[i] - 1;
            for(int j=0; jif(numbers[j] < numbers[i])
                    count--;
            sum += count*factorial(n-i-1);
        }

        return sum;
    }

    //n   
    private static int factorial(int n){
        int total = 1;
        for(int i=1; i<=n; i++){
            total *= i;
        }

        return total;
    }
}

Input & Output
Input the number of digits:
8
Input digits:
2 6 4 5 8 1 7 3
Permutation at: 8227
Next Permutation: 26458317
-------------------------------------
Input the number of digits:
8
Input digits:
8 7 6 5 4 3 2 1
Permutation at: 40319
There is no permutation after: 87654321
-------------------------------------
Input the number of digits:
8
Input digits:
8 7 6 5 4 3 1 2
Permutation at: 40318
Next Permutation: 87654321
-------------------------------------
Input the number of digits:
6
Input digits:
2 3 1 4 5 6
Permutation at: 144
Next Permutation: 231465
-------------------------------------
Input the number of digits:

Reference
王暁東『コンピュータアルゴリズム設計と分析』(第3版)P 45