package com.interview.number;
import java.util.Arrays;
/**
* @author Tushar Roy
* Date 01/21/2016
*
* Given a number n, find mth value in permutation of array consisting of [1..n] values.
* mth is defined by lexicographical order.
*/
public class MthNumberInNSizeArray {
public int[] find(int n, int m) {
boolean used[] = new boolean[n];
int result[] = new int[n];
find(result, used, 0, n, m);
return result;
}
private void find(int result[], boolean used[], int start, int n, int m) {
if(1 == m) {
fillupRemaining(result, used, start);
return;
}
int index = binarySearch(m, start + 1, n, factorial(n - start - 1));
int i = nthUnused(used, index);
used[i] = true;
result[start] = i + 1;
find(result, used, start + 1, n, m - (index-1)*factorial(n - start - 1));
}
private int binarySearch(int m, int start, int end, int factorial) {
int i = 1;
int j = end - start + 1;
while (i <= j) {
int middle = (i + j)/2;
if (factorial*(middle) >= m && factorial*(middle - 1) < m) {
return middle;
} else if (factorial*middle < m){
i = middle + 1;
} else {
j = middle - 1;
}
}
throw new IllegalArgumentException();
}
private void fillupRemaining(int result[], boolean used[], int index) {
int j = 0;
for(int i = index; i < result.length; i++) {
while (true) {
if (!used[j]) {
result[i] = j + 1;
used[j] = true;
break;
}
j++;
}
}
}
private int nthUnused(boolean used[], int n) {
int unused = 0;
for ( int i = 0; i < used.length; i++) {
if (!used[i]) {
unused++;
if (unused == n) {
return i;
}
}
}
throw new IllegalArgumentException();
}
private int factorial(int n) {
int result = 1;
for ( int i = 1; i <= n; i++) {
result = result*i;
}
return result;
}
public static void main(String args[]) {
MthNumberInNSizeArray mn = new MthNumberInNSizeArray();
int n = 5;
int m = 120;
for ( int i = 1; i <= m; i++) {
int result[] = mn.find(n, i);
Arrays.stream(result).forEach(r -> System.out.print(r + " "));
System.out.print("\n");
}
}
}