Next Greater Permutation Of Digits
February 28, 2012
We have another interview question today:
Given a number, find the next higher number that uses the same set of digits. For instance, given the number 38276, the next higher number that uses the digits 2 3 6 7 8 is 38627.
Your task is to write a function to find the next greater permutation of digits. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Please see my plain python solution at: http://codepad.org/cR4jr4Vp
Same algorithm as OP, obviously as it is correct.
I’m pretty sure there’s an error in OP’s solution:
(next-perm 2643) returns 3264 instead of 3246, which would be the smaller next permutation.
Tried my hand at a Haskell solution, but it doesn’t handle all edge cases yet.. will continue later
whelp, this seems to work, but probably doesn’t. Suggestions for improving it are welcome:
Dammit, I don’t get the job.
Here’s some idiomatic Ruby code that does the job:
Here’s the gist of the algorithm:
1 – Find all the permutations which are strictly greater than the input.
2 – Store those numbers in a list for easy retrieval.
3 – Sort the aforementioned list, and return the element in its first position.
Here are two Python solutions.
This one uses brute force. It generates the permutations of the digits in lexicographical order and returns the first permutation that is larger than the argument.
This function analyzes the digits of the number to identify which two digits to swap.
s[:j] is the leading digits which do not change
s[j+1:] is the tail, which is a sequence of decreasing digits at the end of the number
s[j] is the digit to be swapped into the tail
s[k] is the smallest digit in the tail that is > s[j]
Another Haskell solution, I’ve reused DGels number conversion functions.
nextPerm is the generic list permuting function (nextPerm :: Ord a => [a] -> [a]), and nextPermutedNum is the actual solution.
example:
And now C++, mostly low level apart from string and swap.
I’ve used the same algorithm as Tomasz in a few other posts on this site.
I believe the algorithm was discovered as early as 1812! Seems to be most often credited to a couple of German authors named Fischer and Krause. Unfortunately, I can’t find much information regarding the original literature.
If anyone has any further information, I would love to read it
Using the C++ standard library this is much simpler:
Wikipedia (Permutation, Generation in lexicographic order) says: “The method goes back to Narayana Pandita [sic] in 14th century India, and has been frequently rediscovered ever since.”
(sourced to Knuth’s TAoCP 4 fascicle 2, Generating all tuples and permutations, which I have but not at hand now).
(The Wikipedia article on the credited mathematician is about Narayana Pandit (1340–1400). “Pandita” looks like a typo.)
My 2 cents in Haskell, since I’m trying to brush up on (read: learn) it.
brute
is the obvious, slow, brute force option; hopefullyfaster
lives up to its name.Reblogged this on Inspiredweightloss.
I guess it’s mega overkill, but it does the job :)
Recursive, *non-bruteforce* algorithm.
If the recursive call returns a different list, there’s been reordering, so just cons current head to returned value.
Otherwise, find next element to replace current head, cons it to the sorted rest of the list from which the next element has been removed.
Scheme to advance a vector to the lexicographically next permutation, or index out of bounds if there is no such:
I knew I would make msitakes, so I tested it. (I had made an off-by-one, and got a comparison the wrong way around, and even called a procedure with a wrong number of arguments :( Hire me?
It steps the vector so:
#include
#include
#include
using namespace std;
bool myfunction(int m,int n) {
return (m>n);
}
int main() {
int num = 1, i, j, size, * num_array, temp;
while (num != 0) {
cin >> num;
temp = num;
for (i = 1; temp != 0; i++) {
temp /= 10;
}
size = i-1;
num_array = new int[size];
for (i = 0; num != 0; i++) {
num_array[i] = num%10; // array reversed
num /= 10;
}
for (j = 0; j < i; j++) {
temp = num_array[j];
for (int k = j+1; k < i; k++){
if (num_array[k] < temp) {
i = j; // store j in i
j = k-1; // break second loops, store k in j (note i changed)
}
}
}
// extreme case: i = j = k
if (i == j) {
cout << "no solution";
return 0;
}
// put i-th entry to temp, sort 0-th to j-th entries except i-th entry and put into i-th to (j-1)-th entry
// finally put temp to j-th entry
temp = num_array[i];
num_array[i] = INT_MIN;
vector myvector (num_array, num_array + size);
vector::iterator it;
sort(myvector.begin(), myvector.begin() + j + 1, myfunction);
myvector[j] = temp;
num = 0;
temp = 1;
for (i = 0; i < size; i++) {
num += temp*myvector[i];
temp *= 10;
}
cout << num << endl;
}
return 0;
}
within integer range the code should be ok
FWIW, your algorithm is exactly the same as Algorithm L in Knuth’s The Art of Computer Programming, vol 4, section 7.2.1.2. Your explanation of the basic algorithm is much more intuitive and more clear than Knuth’s, though. :-)
If the digits in the number appear in the reverse sorted arrangement (654321), it is the highest number possible with a permutation of those digits. In this case we cannot do anything for the given problem.
If not, we analyze the given number from the last digit onwards, and identify the 2 successive digits which decrease. (34 in 653421)
At this point we splice the digits in two parts and sort the second half (653421 becomes 653 and 124).
We then pick the offending digit which is the point of splice (3 in this case) and swap it with the next highest digit in the second half (654 and 123). Concatenate the digits and you have the number.
Welcome any suggestions. Python implementation below.
adeepak, sorting is overkill. If the first loop hits the break, it found the right digits[x – 1], else the digits were in decreasing order, so return None at that point. The second loop should find the rightmost digits[y] that satisfies the condition; one is guaranteed to exist to the right of digits[x – 1] because digits[x] is one.
Swap digits[x – 1] with digits[y] and the tail after[x – 1] will be in decreasing order, so all the sort does is reverse it. It does reverse it, of course, but it is heavier machinery than is needed.
Jussi,
Thanks for your comment and pointing the overkill. I agree sorting will not be needed as the digit order is implied for the second half. Incorporating your suggestion, the solution becomes more optimal.
Here is a C# solution. Initially I though of the brute fore, generating all permutation, then sorting them to get the next number. That would be painfull. The way I implemented is
this: I liked other approach as suggested by some one, to simply use the digits in the original number and generate a another sequence till you get the next bigger one.
Algorithm
1. Input the n didgit number An
2. Flag = false
3. While Flag = false
An = An +1
Flag = Compare(An, An+1)
4. Return An
1. Compare( A, B)
2. Flag = true
3. for j <–0 to j <– B.Length – 1
If A contains B[j]
else
Flag = false
4. Return Flag
Code:
private static int _getNextNumber(int input)
{
bool found = false;
Stopwatch watch = new Stopwatch();
watch.Start();
char[] digits = input.ToString().ToArray();
while (!found)
{
++input;
found = _compare(input, digits);
}
watch.Stop();
Console.WriteLine("Execution time :- " + watch.Elapsed);
return input;
}
private static bool _compare(int input, char[] digits)
{
bool result = true;
char[] inputArray = input.ToString().ToArray();
if (inputArray.Length != digits.Length)
result = false;
if (result)
{
for (int count = 0; count c == inputArray[count]);
int outputDigitInput = inputArray.Count(c => c == inputArray[count]);
if (repitedDigitInput != outputDigitInput)
{
result = false;
break;
}
}
}
}
return result;
}
Here’s a solution in php.
Logic is as follows:
– start with the rightmost digit (say, n) and see if there’s any digit to its left that is lesser (say, i)
– if there is then swap n and i
– after swapping, sort the digits to the right of n
eg. 123451
– Rightmost digit, 1, is the least – so the next rightmost digit is 5
– 5 is greater than 4, swap to get 123541
– next sort the numbers to the right of 5 (4,1) to get the final number – 123514
You can make this function recursive so that it prints all the permutations possible.
function fn($n)
{
static $count=0;
$len = strlen($n);
$index = $len-1;
$found = false;
while ($index > 0 && !$found)
{
for($i=$index-1;$i>=0&&!$found;$i–)
{
if($n[$index] > $n[$i])
{
$temp = $n[$index]; $n[$index] = $n[$i]; $n[$i] = $temp;
$found = true;
}
if($found)
{
for($j=$i+1;$j<$len-1;$j++)
for($k=$j+1;$k$n[$k])
{
$temp = $n[$j]; $n[$j] = $n[$k]; $n[$k] = $temp;
}
}
}
}
$index–;
}
if ($found)
{
$count++;
echo ” $count: “.$n;
fn($n);
}
}
An algorithm is here:
Loop digits i = (n-2) to 0
Find to the right of i, smallest digit greater than i
if found, 1) swap i with the digit found 2) sort digits after i 3) RETURN permutation formed
End loop
If no swap, greatest number is reached; there is no Next Greater Permutation Of Digits
A simple Java program:
public class NextGreaterPermutationOfDigits {
/**
* @param args
*/
public static void main(String[] args) {
// test nos
//String num = “38276”;
String num = “8756”;
//String num = “382765”;
//String num = “385765”;
// for larger numbers, sorting each time can be a performance hit
// create sequence for look up
char[] sequence = sort(num.toCharArray());
System.out.println(num);
String newNum;
for (int i = 0; i = 0; i–) {
leastGreaterDigitIdx = -1;
for (int j = i + 1; j chars[i] &&
(leastGreaterDigitIdx chars[j])) {
leastGreaterDigitIdx = j;
}
}
if (leastGreaterDigitIdx > i) {
// swap i with leastGreaterIdx
temp = chars[i];
chars[i] = chars[leastGreaterDigitIdx];
chars[leastGreaterDigitIdx] = temp;
// sort digits after i
// digits to be sorted
char[] toBeSorted = new char[chars.length – 1 – i];
int toBeSortedIdx = 0;
for (int k = i + 1; k < chars.length; k++) {
toBeSorted[toBeSortedIdx++] = chars[k];
}
// look up sequence for sorting
int idx = i + 1;
for (int x = 0; x < sequence.length; x++) {
for (int k = 0; k there is no Next Greater Permutation Of Digits
return num;
}
private static char[] sort(char[] chars) {
char[] result = chars.clone();
char temp;
for (int k = 0; k < result.length; k++) {
for (int j = 0; j result[j + 1]) {
temp = result[j];
result[j] = result[j + 1];
result[j + 1] = temp;
}
}
}
return result;
}
}
#include
#include
#include
#include
using namespace std;
int compare (const void * a, const void * b)
{
return ( *(const char *)a > *(const char *)b);
}
int myfunc(char *num)
{
int i,length;
for(i=0;num[i];i++);
length=i;
int prev=num[length-1];
for(i=length-2;i>=0;i–)
{ if(prev>num[i])
break;
prev=num[i];
}
if(i==-1)
return -1;
int pos=i;
int min_pos=length-1;
for(i=length-1;i>pos;i–)
{ if(num[i]>num;
if(myfunc(num)==0)
cout<<num;
else
cout<<"sorry";
}