I want to create a random String of numbers.
From 0-9.
10 digits long.
First digit cannot be a 0.
One of the digits has to be in the String 2 times and one has to not be there at all.
Or one digit has to be there 3 times, and 2 other digits can not be there at all.
To make this a little bit clearer here are some examples:
1223456789 - 10 digits, no starting zero, one digit (2) is there 2 times and one digit (0) is not there at all
1000345678 - 10 digits, no starting zero, one digit (0) is there 3 times and two digits (2,9) are not there at all
The starting zero is pretty easy caught with startsWith - method, but I have not found a way to check for the rest and I am not particularly good at regex while I am also not entirely sure you can even do this using regex.
For generating the random String itself, I have worked with the Random class as well as RandomStringUtils, both of which don't have restrictions on creating numbers.
Has anyone of you an idea how to achieve this?
Imagine you have 10 sacks, each one of them has its corresponding number embroided on it, from 0 to 9, like this:
.---.._
{------';
}====={
.´ '.
/ .´| \ inside there are
| | | <--- stones with '1' engraved
\: _|_ /
-__ =.´
You also have a coin to flip heads or tails on your hand.
.------..-
´ . /___ `.`.
; / / ´} ; ; ______________________________
: "|'__' // : : / |
' .|/__\. } \ ' ' /_ HEAD! You shall pick 3 |
' /"../ ' ' | stones from the 1st sack! |
; / \/ ͷ ; ; \____________________________/
`_/ ´ ´
" -------´-´
First, we will decide if we will have 3 repeating numbers or 2 repeating numbers. Flip the coin to decide! Tail is 3, Head is 2. We will call this result ͷ.
Remove the sack embroided with 0 (Zero) for a moment.
Now pick ͷ (2 or 3) stones from a random sack of the 9 sacks you have in front of you. Remember, you cannot start with 0, that is why we removed it for a moment! Remove the sack you just picked from the line of sacks, forever. You cannot pick from this one anymore. Put back the 0 (Zero) sack on the line.
Place one of the stones you just picked in front of yourself. Hold ͷ-1 in your hand.
Now repeat this until you have 9 stones in your hand:
Select a random sack, pick ONE stone from it and hold it in your hand. Remove the sack from the
line.
By the end of this process, you will have 9 stones in your hand, one in front of yourself. Shuffle up the ones in your hand. Place them in a straight line in front of yourself, next to the stone that was already in front of you.
You will end with 10 numbers, ͷ repetitions of the same number, won't start with zero, and the remaining sack(s) in front of you are just a side-effect of removing the sacks along the way.
What about trying to make what you want first using the rules then construct the rest.
Here is a possible idea
Using the first rule
One of the digits has to be in the String 2 times and one has to not be there at all.
Create a LinkedList then add the numbers 1 to 9 to it.
Generate a random number between 0-8 (range of the indexes of the list), use the index to retrieve a value out of the list (as in delete it) then add that to the String so the first number isn't 0.
Add 0 back to the list so it can be used somewhere else.
There are now 9 numbers left in the LinkedList with the first number being non zero and already in the String variable as per step 2. From here, generate another random number in the range of the LinkedList indexes. Whatever this number is, remove it from the LinkedList add it twice to the ArrayList.
There are now 8 numbers left in the LinkedList, 1 non zero number in the String. and 3 numbers in the ArrayList for a total of 4 numbers in your sequence that are confirmed to be correct. You have to get another 6 numbers to complete it. So far it would look something like this.
String sequence => "4"
ArrayList beingBuilt => [2, 6, 6]
LinkedList available => [1, 3, 4, 5, 7, 8, 9, 0]
Seems you only can have 10 numbers, loop 6 more times through the LinkedList using a random number to pluck at a random index, delete it from LinkedList add it to ArrayList.
After this the ArrayList should have 9 numbers, you could shuffle it to make it more random then convert it to a String and append to on the end of the sequence. Your rule should be satisfied now.
To make it more random you could manipulate how you pluck out numbers from the LinkedList and also the last rule you had you could change it for that too fairly simply. I used a LinkedList due to faster deletes, I did think about using a set but perhaps more work to handle the random number index being mapped to a number that actually exists in the set.
Just an idea though
The idea is: first generate a random string with 0-9 each once and not starts with 0, then: 1. replace one of the digital will another or 2.replace two digitals with another.
import java.util.Random;
public class Main {
public static void main(String[] args) {
System.out.println(generateRandomString());
System.out.println(generateRandomString());
}
public static String generateRandomString() {
String alphabet = "0123456789";
String result = "";
Random random = new Random();
// build a random string construct will 0-9 and each digital appear once
for (int i = 0; i < 10; i++) {
int index = random.nextInt(alphabet.length());
if (i == 0) { // first cannot be 0
index = random.nextInt(alphabet.length() - 1) + 1;
}
String c = alphabet.substring(index, index + 1);
result += c;
alphabet = alphabet.replace(c, "");
}
return random.nextInt(2) == 0 ? shuffle1(random, result) : shuffle2(random, result);
}
// One of the digits has to be in the String 2 times and one has to not be there at all.
private static String shuffle1(Random random, String result) {
int from = random.nextInt(10);
int to = random.nextInt(9) + 1;
while (from == to) {
to = random.nextInt(9) + 1;
}
result = result.replace(result.substring(to, to + 1), result.substring(from, from + 1));
return result;
}
// One digit has to be there 3 times, and 2 other digits can not be there at all
private static String shuffle2(Random random, String result) {
int from = random.nextInt(10);
int to1 = random.nextInt(9) + 1;
int to2 = random.nextInt(9) + 1;
while (from == to1) {
to1 = random.nextInt(9) + 1;
}
while (from == to2 || to2 == to1) {
to2 = random.nextInt(9) + 1;
}
result = result.replace(result.substring(to1, to1 + 1), result.substring(from, from + 1));
result = result.replace(result.substring(to2, to2 + 1), result.substring(from, from + 1));
return result;
}
}
If you're not too concerned about performance then the simplest thing would be to just generate random lists of numbers and check them against your conditions until you get one that works. Best to do the filtering as numbers and then convert to a string at the end rather than using regular expressions.
public String getRandomInts() {
Random random = new Random();
int[] ints;
do {
ints = random.ints(10, 0, 10).toArray();
} while (!meetsCriteria(ints));
return Arrays.stream(ints).mapToObj(String::valueOf).collect(Collectors.joining(""));
}
private boolean meetsCriteria(int[] ints) {
if (ints[0] == 0) {
return false;
}
if (frequency(ints, 0) == 1
&& frequency(ints, 1) == 8
&& frequency(ints, 2) == 1) {
return true;
}
if (frequency(ints, 0) == 2
&& frequency(ints, 1) == 7
&& frequency(ints, 3) == 1) {
return true;
}
return false;
}
private int frequency(int[] ints, int count) {
return (int) IntStream.range(0, 10)
.filter(n1 -> Arrays.stream(ints).filter(n2 -> n1 == n2).count() == count)
.count();
}
Related
Given an int in Java, I want to be able to determine the digit in the hundreds place of the number. For example:
an input of 124 should give an output of 1
an input of 357 should give an output of 3,
an input of 653 should give an output of 6.
I have tried the code below, but am getting the following error:
The operator / is undefined for the argument type(s) boolean, int
Here is my code:
import java.util.Random;
class adam{
public static void main(String[]args)
{
Random rnd = new Random();
int first = rnd.nextInt(900)+100;
int second = rnd.nextInt(900)+100;
int third = rnd.nextInt(900)+100;
System.out.println(first);
System.out.println(second);
System.out.println(third);
if ((first==second&&first==third)/100);
System.out.println(first);
System.out.println(second);
System.out.println(third);
}
}
Question
How can I get the digit in the hundreds place value from a Java int?
Why am I getting this error in my code?
Let me guess, you probably want something along these lines:
if (first / 100 == second / 100 && first / 100 == third / 100) {
System.out.println(first / 100);
System.out.println(second / 100);
System.out.println(third / 100);
}
This will print the same value three times if the condition is true, though, which may not be exactly what you want. For example, if the numbers are 756, 723 and 792, it will print 7 three times. Anyway, you can try it out, see if you can modify it to your needs, and if not, explain where I guessed wrong.
Edit: to reduce the number of divisions you can alternatively just divide all the values by 100 before the if statement:
first /= 100; // or if you prefer: first = first / 100;
second /= 100;
third /= 100;
if (first == second && first == third) {
System.out.println(first);
System.out.println(second);
System.out.println(third);
}
How can I get the digit in the hundreds place value from a Java int?
You're on the right track with your integer division. You've also got the modulo operator at your disposal for handling numbers >= 1000.
Easiest to just show the math, this should be enough for you to go on:
2468 (1) start with an integer, 2468
2468 / 100 = 24 (2) divide by 100 to discard 10's and 1's
24 % 10 = 4 (3) modulo 10 to discard 1000's and higher
4 (4) and your left with your 100's digit
As you can see, you could stop at (2) if you know you won't see numbers >= 1000. As an aside, you'd want to take the absolute value first if you have to deal with negative numbers.
Why am I getting this error in my code?
Because this statement is nonsense:
if ((first==second&&first==third)/100);
In particular the condition is:
(first==second&&first==third)/100
And if you split it into its parts you can see what is happening:
first == second (1) == produces a boolean
first == third (2) == produces a boolean
(1) && (2) (3) && produces a boolean
100 (4) 100 is an int
(3) / (4) (5) now you have boolean / int
And you can't divide a boolean by an int.
How can I get the digit in the hundreds place value from a Java int?
This code is working:
import java.util.Random;
class Adam{
public static void main(String[]args)
{
Random rnd = new Random();
int first = rnd.nextInt(900)+100;
int second = rnd.nextInt(900)+100;
int third = rnd.nextInt(900)+100;
System.out.println(first);
System.out.println(second);
System.out.println(third);
int first1=first/100;
int second1=second/100;
int third1=third/100;
System.out.println("an input of "+first +" an output of "+first1 +" first");
System.out.println("an input of "+second +" an output of "+second1+" first");
System.out.println("an input of "+third +" an output of "+third1+" first");
}
}
Why am I getting this error in my code?
--->The boolen can't devided by an int
All you need is the third last digit in the number.
So you can try this:
String temp = number + "";
System.out.println(temp.charAt(temp.length() - 3));
Hello everyone I was having some issue splitting up a user input number using printf (I do have to use printf). My problem is that when I put in say the number 12345 it will print the integers on five separate lines, and also has them in the reverse order. So it would look something like this when I put in the integer 12345:
5
4
3
2
1
But without the spaces (I need those as well). I want it to print like this: 1 2 3 4 5.
Here is the code I have so far:
public static void main(String[]args){
Scanner input = new Scanner(System.in);
int one;
System.out.print("Enter the five digit integer you would like to be split up:");
one = input.nextInt();
while (one > 0){
System.out.printf("%d%n", one % 10);
one = one /10;
}
}
First, in order to avoid printing on separate lines, you should avoid using the %n formatting character in your printf().
Now, how do you print the digits in the correct order? Well, since you are limited to five-digit numbers, you can do something like this:
for ( int divisor = 10000; divisor >= 1; divisor /= 10 ) {
System.out.printf( "%d ", n / divisor);
n %= divisor;
}
System.out.printf( "%n" ); // Just to complete the line
(divisor /= 10 is shortcut for divisor = divisor / 10, and n %= divisor is shortcut for n = n % divisor).
So you start by dividing the number by 10000. This will give you the fifth digit from the right. Then you take the remainder and put it in n. This gives you just the remaining four digits. Then the loop will reduce your divisor to 1000, which will take the fourth digit from the right, and you keep doing that until you reach a divisor of 1.
Another approach that does not require knowing that the number is 5 digits long, but requires recursion is to write a method like so:
public static void printSplitNumber( int n ) {
if ( n == 0 ) {
return;
}
printSplitNumber( n / 10 );
System.out.printf( "%d ", n % 10);
}
And from your main, call:
printSplitNumber(n);
System.out.printf("%n"); // Again, just completing the line.
This recursive method relies on the fact that you print the current digit only after all the rest of the number has been printed. So this causes it to print it to the right of the rest of the digits, giving you the effect you need.
Unless the assignment is to figure out how to split the digits numerically, I think that the simplest approach is to either use Scanner's nextLine() method to get a String, or convert your int to a String, and then split the characters of the String.
substring() is a little heavy - a lighter-weight way to do it is by inspecting character positions, like this:
public void printDigits(String chars) {
for(int i = 0; i < chars.length(); i++) {
System.out.printf("%c ", chars.charAt(i));
}
}
This approach uses the substring method as opposed to mathematically manipulating the int value.
int one;
System.out.print("Enter the five digit integer you would like to be split up:");
one = input.nextInt();
String x = Integer.toString(one);
for(int i = 0; i < x.length() - 1; i++)
{
// On last digit in number
if(i + 1 == x.length())
{
System.out.printf("%s ", x.substring(x.length()));
}
else
{
System.out.printf("%s ", x.substring(i, i + 1));
}
}
Simplified printf statemnts thanks to #Jerry101's comment
I have to write a code for printing all palindrome numbers up to 1000. Here is my code. I have dealt with 3 scenarios:
1-digit number
2-digit number
3-digit number
My third scenario is not printing just the palindromes but prints all the numbers. A hint will help me solve this.
public class PrintPalindrome {
public static void main(String args[])
{
Integer[] array=new Integer[1000];
for(int i=0;i<array.length;i++)
{
array[i]=i+1;
printPalindrome(array[i]);
//System.out.println(array[i]);
}
}
public static void printPalindrome(Integer a)
{
String num=Integer.toString(a);
int length=num.length()-1;
//System.out.println(num);
if(num.length()<=1)
{
System.out.println("" + num);
}
else if(num.length()==2)
{
if(num.charAt(0)==num.charAt(1))
System.out.println(num);
}
else if(num.length()>2)
{
//now deal with the numbers whose length is greater than 2
for(int i=0;i<=length;i++)
{
if(num.charAt(i)==num.charAt(length-i))
System.out.println(num);
}
}
}
}
Work out a solution with arithmetic…
This doesn't necessarily help with the code that you've already got, but it's approach to the problem in the title, How to print all palindromes upto 1000, which may be helpful to others who come across this question. It's often fun to try to solve these problems using the properties of the numbers, without worrying about converting them to strings. In this case, note that for any number n, you can get the leading digit by n % 10, that is, the remainder of n divided by 10, or n modulo 10. You can get the number whose digits are the same as the remaining digits of n as the integer quotient of n/10. E.g.,
1234 % 10 = 4
1234 / 10 = 123
Now, if you keep applying this deconstruction, you can get the individuals digits:
123 % 10 = 3
123 / 10 = 12
12 % 10 = 2
12 / 10 = 1
1 % 10 = 1
1 / 10 = 0
Now, if you take those numbers in the same order that you got them (4, 3, 2, 1), you can reconstruct the "reverse" number:
1 + 10(2 + 10(3 + 10(4 + 0))) = 4321
If we call this the reverse of a number, then number is a palindrome if and only if it's equal to it's reverse.
…and then translate it to Java
This is fairly straightforward to implement in Java, and it doesn't require any special casing about 1-digit numbers, 2-digit numbers, etc., or string manipulation. (As Kent points out in the comments, there's still a limit on how large the numbers that this handles is, but if you need to handle big numbers, you could (i) switch to a long; (ii) switch to a BigInteger.)
public class PalindromeExample {
/**
* Returns the number whose digits (base 10) are the reverse
* of number's (with no leading zeros).
* #param number the number to reverse
* #return the reversed number
*/
public static int reverse( int number ) {
int result = 0;
while ( number > 0 ) {
result = result * 10 + (number % 10);
number = number / 10;
}
return result;
}
/**
* Show the numbers less than 10000 whose digit sequences
* are palindromes.
*/
public static void main(String[] args) {
for ( int i = 0; i < 10000; i++ ) {
if ( i == reverse( i ) ) {
System.out.println( i );
}
}
}
}
0
1
2
3
…
9
11
22
…
99
101
111
…
151
161
…
8008
8118
…
9339
9449
9559
9669
9779
9889
9999
if(num.charAt(i)==num.charAt(length)-i)
is wrong. Even if you set parenthesis in the "right" place you still be wrong, because for example:
charAt(0) == charAt(3) //and what's char at 3?
if(num.charAt(i)==num.charAt(length-i-1))
should do the trick but then placing it in a for loop doesnt make any sense.
When a 3-digit number has 1st and 3rd digit the same it is actually a palindrome. Every other loop will just mess up your output.
For the requirement, we don't have to convert to string.
pls try if this works for you: (could be an one-liner)
for (int i = 1; i < 1000; i++)
if (i<10 ||(i<100&&i%11==0)||(i>100&&i%10==i/100) )
System.out.println(i);
Handling scenarios for each digit length to check if a number is a palindrome is not an appropriate approach.
Trying what the other answers suggest - like going through each and every number and checking if it is palindrome by reversing number digit by digit is better but even then it is not very efficient as it is brute force.
So, I would like to some suggestions if I may:-
Rather than going for brute force, any other approach if possible is preferable.
Even while resorting to brute force, using the library functions is
better and at least as efficient as any code we can write. ex - Integer.reverse() function for reversing an integer.
I have had a try at generating the palindromes(rather than trying one by one). This is not bug-proof yet as I have not tested extensively but should be able to convey the concept.
public class PrintPalin {
public static void main(String[] args) {
// TODO Auto-generated method stub
//The first palindrome = 1
int i = 1;
while(i<=10000){
System.out.println(i);
i = nextPalin(i);
}
}
static int nextPalin(int i){
StringBuilder sb = new StringBuilder(String.valueOf(i));
int len = sb.length(), right = len/2, left;
if(len%2!=0 || len == 1){
left = right;
}else{
left = right-1;
}
//System.out.println(left + " " + right);
while(right<len && sb.charAt(right)=='9'){
sb.setCharAt(right, '0');
right++;
sb.setCharAt(left, '0');
left--;
}
if(right==len){
sb.insert(0, '1');
//sb.append("1");
sb.setCharAt(right, '1');
}else{
sb.setCharAt(right, (char)(sb.charAt(right)+1));
if(right != left){
sb.setCharAt(left, (char)(sb.charAt(left)+1));
}
}
i = Integer.valueOf(new String(sb));
return i;
}
}
Where the above approach wins is when the density of palindromes per number tried is less when we go for higher numbers but for the range that is asked(0 to 1000) it would not be able to make much difference.
I am open to other approaches. I was thinking may be decoding the addition required to generate the next palindrome number should be faster and better approach instead of using strings the basic idea of both approaches are similar so should not be much difficult(though I am not sure).
I believe you want to check whether the number is a palindrome or not before you print it. You just need to seprate checking and printing like this:
if(num.length()>2)
{
boolean isPalindrome=true;
for(int i=0;i<=length/2;i++) //you compare one half, to the other
{
if(num.charAt(i)!=num.charAt(length-i))
isPalindrome=false;
}
if(isPalindrome)
System.out.println(num);
}
This should work for a number of any length.
Help me to understand how this code works. It essentially adds commas into a string of numbers. So if the user types a 1 to 3 digit number it is unchanged. For a four digit number ,it adds a comma so
1111 becomes 1,111
11111 becomes 11,111
111111111 becomes 11,111,111
and so on. Here's the code:
private String addCommasToNumericString (String digits)
{
String result = "";
int len = digits.length();
int nDigits = 0;
for (int i = len - 1; i >= 0; i--)
{
result = digits.charAt(i) + result;
nDigits++;
if (((nDigits % 3) == 0) && (i > 0))
{
result = "," + result;
}
}
return (result);
}
I´ll explain what I do understand of it
The for loop basically counts the length of the number the user has written to avoid putting a comma before the first number (e.g. ,1111). And while i is less than the length of the string it subtracts 1.
result returns the char at position i, since it counts downwards it returns the chars "opposite" from right towards left.
nDigits adds 1 from to the initial value of 0 on each iteration through the loop.
I guess now is where I am having trouble seeing exactly what is going on: if ("nDigits % 3) == 0.
So for the two first iteration through loop it will not execute the if loop because:
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
nDigits starts out as 1 because of the nDigits++ code inside the for loop, so how does it put the comma after three digits and not two? And how does it know when there is only 4 or 5 digits to place the comma corretly at position 1 and two (1,111 - 11,111)?
I think the easiest way to explain this is to slow it down to each pass.
The loop starts at the end of the string so if you have the string 12345, then after the first time through the loop result will be "5" and nDigits will be 1.
The next time through, '4' will be added to the front of the result giving you "45" and nDigits will be 2.
The third time through, it adds '3' to the front of result making that "345" and then the if-then triggers and adds a comma to the front. Result is now ",345".
More passes will give you "12,345".
I think what is confusing you is that loop starts at the '5' and not at the '1'. Everything is added to the front of result and not to the end as you would normally expect.
Hope this helps!
The key thing in this method is to count the digits from right to left. If you don't do it that way it won't work.
You can also do the same with String Manipulation instead of char manipulation. Maybe it makes it easier to understand so I'll provide an example.
My solution involves the use of the subString Method and operates in a similar manner to yours. Starting FROM RIGHT TO LEFT, it divides the original String in two substrings and adds a comma in between them every time there is a 3 digits group.
private String addCommas (String digits) {
String result = digits;
if (digits.length() <= 3) return digits; // If the original value has 3 digits or less it returns that value
for (int i = 0; i < (digits.length() – 1) / 3; i++) {
int commaPos = digits.length() – 3 – (3 * i); // comma position in each cicle
result = result.substring(0, commaPos) + "," + result.substring(commaPos);
}
return result;
}
The variable result is used for incremental build of the final output, in each iteration one or two chars are concatenated from left (i.e. the string is build from right to left).
One char is concatenated everytime by running
result = digits.charAt(i) + result;
it is the actual digit
the second char is concatenated in each third iteration by running
result = "," + result;
it is the order separator
The implementation is not optimal at all, because in Java the string are immutable and result = "," + result; ends up in creating a new object. The StringBuffer or StringBuilder are far more effective for this purpose.
Essentially what this does is start at the last digit of the number and iterate through from right to left, prepending them to the result String and putting a comma in every 3 characters.
In this particular code, len holds the total length of the number and nDigits is a count of how many of those digits have been evaluated already. Starting at position len-1 (so the index of the last digit of the number), the for-loop iterates through position 0 (the first digit of the number). It takes the digit at position i, puts it at the front of the result String, and then evaluates if there should be a comma in front of it. nDigits % 3 will return 0 every 3rd digit, so the if statement evaluates if there should be a comma by checking that if there have been 3 digits written and the one you just wrote was not 0.
for (int i = len - 1; i >= 0; i--)
i starts with len - 1, to start from the last digit. i > 0 in if (((nDigits % 3) == 0) && (i > 0)) is the one that avoid a comma before the first number (e.g. ,1111).
I modified answer of #Antonio Ricardo Diegues Silva for my purposes.
/**
* Get number in {#link String} with divider after 'n' number of digits
* #param number number for processing
* #param n amount after which will be inserted divider
* #return {#link String} number with dividers
*/
public static <T extends Number> String insertDividerBetweenEveryNDigits(T number, int n, String divider) {
StringBuilder builder = new StringBuilder().append(number);
int digitsNumber = builder.length();
if (digitsNumber > n) { // If the original value has n digits or less it just returns that value
for (int i = 1; i <= (digitsNumber - 1) / n; i++) {
int dividerPos = digitsNumber - (n * i); // divider position in each cycle
builder.insert(dividerPos, divider);
}
}
return builder.toString();
}
I have strings of the form 000011122222. That is, consecutive digits repeated random no. of times. Some other examples could be:
0011122223333
01222
00011234444
001122222
and so on. I know, say for a string 01222, that a total of 5!/3! permutations are possible. I need to generate all these permutations for each such string.
I have tried generating permutations by various methods. One is by generating all the possible permutations (just as for strings without repetition), but since the strings that I would be using can be very large this can waste time generating too many redundant permutations.
Secondly, I have tried placing the digits at random indices of a character array equal to the size of the string and terminating the loop when the count of digits is same as in the input string. However, this way I am wasting a lot of memory and also taking up a lot of time.
I need an efficient way to generate permutations for such strings. Just an algorithm or code, either is welcome. I am using Java.
Thanks!
One of the standard algorithms for generating permutations is an algorithm for listing them in lexicographically increasing order. This algorithm, which is used by most implementations of the C++ std::next_permutation algorithm, generates permutations in at most O(n) time per permutation and skips over all permutations that are duplicates of one another. It's also extremely easy to code up.
Hope this helps!
Instead of permuting the original string of digits, permute the digit groups. I don't know how best to describe it so I'll try some psuedocode.
For the string "001222" the digit groups are two 0s, one 1, and three 2s.
permute(groups, permutation):
if there are no non-empty groups
print permutation
else
for each non-empty group
permutation += group.digit
--group.count
permute(groups, permutation)
By looping over groups rather than all digits, it avoids generating duplicates because each digit can be chosen only once for the next position rather than multiple times. Walking through a random permutation you get
Permutation Digit Groups
0: 2, 1: 1, 2: 3 // start
0 0: 1, 1: 1, 2: 3
02 0: 1, 1: 1, 2: 2 // *
021 0: 1, 1: 0, 2: 2 // the 1 group is removed from the set
0212 0: 1, 1: 0, 2: 1
02120 0: 0, 1: 0, 2: 1 // the 0 group is removed from the set
021202 0: 0, 1: 0, 2: 0 // the 2 group is removed from the set
Now unroll back to *.
02 0: 1, 1: 0, 2: 1
Because you are looping over digit groups rather than all the (repeated) digits from the original string, you cannot choose 2 again. This means all the permutations beginning with "02" will be unique because the prefix "02" is generated only once. The same applies throughout the algorithm.
Update
Here's a quick PHP implementation which produces 60 permutations for the input "001222":
function permute(&$groups, &$count, $permutation) {
$done = true;
foreach ($groups as &$group) {
if ($group[1] > 0) {
--$group[1];
permute($groups, $count, $permutation . $group[0]);
++$group[1];
$done = false;
}
}
if ($done) {
echo $permutation . PHP_EOL;
++$count;
}
}
$groups = array(
array(0, 2),
array(1, 1),
array(2, 3),
);
$count = 0;
permute($groups, $count, '');
echo "\nTotal: $count\n";
You can create the strings by randomly choosing the count of digits. Like this:
length : int - Total string length
digits : int - maximum digit to include in the string
string : String - the return value
for(i : int from 0 to digits)
{
remainingChars : int = length - length(string) //remaining chars in string
remainingDigits : int = digits - i + 1
count : int = Random from 1 to (remainingChars - remainingDigits + 1)
Append count times i to the string
}
i don't know exactly what you're trying to say, but i once needed a version of permutation where i had a set of numbers like 012 and all the permutations were:
012 021 102 120 201 210
in order to achieve this, i looked up on wikipedia http://en.wikipedia.org/wiki/Permutation
to find the algorithm, then i just created a method for it like this:
public static boolean Permute(int[] a) {
int k, l, n = a.length -1;
for (k = n -1; ; k--) {
if (k == -1)
return false;
if (a[k] < a[k + 1])
break;
}
for (l = n; l >= 0; l--) {
if (a[k] < a[l]) {
int opt = a[l];
a[l] = a[k];
a[k] = opt;
break;
}
}
for (int i = k + 1, j = n; i < j; i++, j--) {
int opt = a[i];
a[i] = a[j];
a[j] = opt;
}
return true;
}
I can help you if you're more specific