I'm writing a MasterMind program in Java. My intention was to generate a 4 digit number, but all digits need to be different. How would you do that using Math.random()? Or is there a better way?
example:
4321 (allowed)
4341 (not allowed)
You can simply achieve this using Collections.shuffle method.
List<Integer> l = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Collections.shuffle(l);
Integer result = 1000*l.get(0) + 100*l.get(1) + 10*l.get(2) + l.get(3);
Using Maps gives you cleaner code and better complexity
public static void main(String[] args) {
Set<Integer> fourUniqueRandonNumbers = new HashSet<Integer>() ;
int maxItems = 4;
StringBuilder flatValueToRetun = new StringBuilder();
while (fourUniqueRandonNumbers.size()<maxItems){
int randomNumber = (int )(Math.random() * 9 + 1);
if(!fourUniqueRandonNumbers.contains(randomNumber)){
fourUniqueRandonNumbers.add(randomNumber);
flatValueToRetun.append(randomNumber);
}
}
}
Use Collections to determine that you already have this digit:
import java.util.ArrayList;
public class MyRandom {
public static void main(String[] args) {
System.out.println(getRandom(4));
System.out.println(getRandom(4));
System.out.println(getRandom(10));
}
public static String getRandom(int length){
if (length>10) return "Hexadecimal?";
ArrayList<Integer> numbers=new ArrayList<Integer>();
while (length>0){
int digit=(int)(Math.random()*10);
if (numbers.contains(digit)) continue;
numbers.add(digit);
length--;
}
StringBuilder sb=new StringBuilder();
for (Integer integer : numbers) {
sb.append(integer);
}
return sb.toString();
}
}
Nothing really optimized here, but :
the simple/brutal way would be to generate digit by digit, and as you store them, as long as you get a digit you already have, you'll generate a new random digit.
A better solution would be to initially store the possible digits (let's say in a list), and for each digit you would get a random number up to the size of the list (minus 1 as list starts at 0), get the element at this position, and remove the element from the list.
Example :
Possible digits : 123456789
picks a random element, let's say "3"
Possible digits : 12456789
and so on.
There are probably many ways to solve this problem, I have provided two below.
First one:
Using a random generator, add random digits from 1-9 to a set.
Set prevents duplicates, so continue generating until the set size is 4.
Second one:
Add the digits 1-9 to an ArrayList, use Collections.shuffle to shuffle the numbers.
Take the first 4 numbers.
Note: Not using the digit 0, to prevent 0123 from becoming 123.
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
public class QuickTester {
public static void main(String[] args) {
for(int i = 0; i < 3; i++) {
setRandom();
}
for(int i = 0; i < 3; i++) {
shuffleRandom();
}
}
/**
* Use a random generator, generate digits from 1-9,
* add them to the set (prevents duplicates) until set size is 4
*/
public static void setRandom() {
Random rand = new Random();
Set<Integer> set = new HashSet<Integer>();
while(set.size() < 4) {
set.add(rand.nextInt(9)+1);
}
String numStr = "";
for(Integer n : set) {
numStr += n;
}
int num = Integer.parseInt(numStr);
System.out.println(num);
}
/**
* Add digits 1-9 to an ArrayList, shuffle it using Collections.shuffle
* Take the first 4 digits
*/
public static void shuffleRandom() {
List<Integer> intList = new ArrayList<Integer>();
for(int i = 1; i < 10; i++) {
intList.add(i);
}
Collections.shuffle(intList);
String numStr = "";
for(int i = 0; i < 4; i++) {
numStr += intList.get(i);
}
int num = Integer.parseInt(numStr);
System.out.println(num);
}
}
Output:
3459
1359
2589
3456
2198
2153
So you want to choose between 4 things, then the 3 remaining, then the 2 remaining, now take the last . How about:
n1 = generator.nextInt(4)+1;
n2 = generator.nextInt(3)+1;
if (!n2<n1) {n2 += 1;}//avoid the hole
n3 = generator.nextInt(2)+1;
if (!n3<n1) {n3 += 1;}//avoid the holes
if (!n3<n2) {n2 += 1;}
Related
What I am trying to do is generate random number but no repetition i'm coding above is it correct?
public static void main(String[] args) {
ArrayList<Integer> arrayLast = new ArrayList<Integer>();
for (int arrayitems : getArray(10, 100)) {
arrayLast.add(arrayitems);
}
}
public static ArrayList<Integer> getArray(int arraysize, int range){
ArrayList<Integer> array = new ArrayList<Integer>();
ArrayList<Integer> arraybase = new ArrayList<Integer>();
Random rnd = new Random();
for (int i = 1; i <= range; i++) {
arraybase.add(new Integer(i));
}
int k =0;
for (int j = 0; j < arraysize; j++) {
if(range>arraysize) {
int sayi = rnd.nextInt(range-arraysize);
array.add(arraybase.get(sayi));
arraybase.remove(sayi);
}
else {
int sayi = rnd.nextInt(arraysize-k);
array.add(arraybase.get(sayi));
arraybase.remove(sayi);
k++;
}
}
Collections.shuffle(array);
return array;
}
Your logic is unnecessarily complex. A simpler way is as follows:
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> set = new HashSet<Integer>();
final int SIZE = 10;
final int RANGE = 100;
Random random = new Random();
while (set.size() != SIZE) {
set.add(random.nextInt(RANGE));
}
System.out.println(set);
}
}
A sample run:
[83, 67, 86, 39, 56, 26, 92, 60, 13, 94]
Note that a Set keep only unique values. So, any duplicate random number added to it will be automatically discarded.
Alternatively,
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
final int SIZE = 10;
final int RANGE = 100;
Random random = new Random();
List<Integer> list = IntStream.generate(() -> random.nextInt(RANGE)).distinct().limit(SIZE).boxed()
.collect(Collectors.toList());
System.out.println(list);
}
}
A sample run:
[54, 62, 14, 5, 30, 76, 7, 9, 63, 61]
Using Stream API in Java 8+, you can generate n distinct integers with a range from origin (inclusive) to bound (exclusive) by using this method:
public static List<Integer> randomInts(int n, int origin, int bound) {
return ThreadLocalRandom.current().ints(origin, bound)
.distinct()
.limit(n)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
}
Example:
// generate 15 distinct random numbers greater than or equal to 10 and less than 90
List<Integer> randoms = randomInts(15, 10, 90);
I recommend doing it this way. If the size and range are significantly different then using sets or streams with distinct is fine. But if the size and range are close those methods can take a relatively long time to complete.
The downside to this algorithm is that it initializes an internal array first. I find this is insignificant in most cases and the increase in speed for large values of both size and range is very significant.
It works as follows:
assume an array of ints from 0 to N.
generate a random int k between 0 and N
assign that value to the return array.
replace the k'th value with the Nth value
then decrease N by 1
and repeat until N == 0
Since k has been effectively removed from the list of available values and replaced with the unassigned Nth value, that value will never be selected again.
public static int [] getRandom(int size, int range) {
Random r = new Random();
int[] ret = new int[size];
// initialize number pool
int[] nums = IntStream.range(0,range).toArray();
for (int i = 0; i < size; i++) {
int k = r.nextInt(range);
ret[i] = nums[k];
range--;
nums[k] = nums[range];
}
return ret;
}
To test this, I recommend the following. The set is filled just to show there are no duplicates. Ironically, filling the set to prove a point takes more time than the actual generation of values.
int[] v = getRandom(10_000_000, 10_000_000);
System.out.println("Done! Filling set");
Set<Integer> set = Arrays.stream(v)
.boxed()
.collect(Collectors.toCollection(LinkedHashSet::new));
System.out.printf("%,d%n",set.size());
System.out.printf("%,d%n",v.length);
Prints
Done! Filling set.
10,000,000
10,000,000
Suggest I have the following array :
{2,3,4,5,11,6} and I'd like to know if any items of the array contain a sum of the number x.
For example:
x=10, then the output would be {2,3,5} and {4,6}.
x=13, then the output would be {2,11},{3,4,6} and {2,5,6}
What would be an optimal algorithm to solve this problem?
I have thought of solving this using the possible permutations of the array, and check whether the sum of the beginning of each permutation equals to the X, but it doesn't seem to solve it.
Thanks!
My two cents solution
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(2, 3, 4, 5, 11, 6);
Collections.sort(list);
Integer sum = 0;
Integer max = 13;
for (int i=0; i<list.size(); i++) {
sumNext(list, i, sum,max, new ArrayList<Integer>());
}
}
private static void sumNext(List<Integer> list, int pos, Integer currentSum, Integer max,
List<Integer> currentElement) {
int nextSum = currentSum + list.get(pos);
if (nextSum > max) {
return;
}
currentElement.add(list.get(pos));
if (nextSum == max) {
for (Integer i : currentElement) {
System.out.print(i);
System.out.print(" ");
}
System.out.println();
} else if (nextSum < max && list.get(pos) < max - currentSum) {
// as array is sorted if current element is higher than the diff
// between currentSum and max there is no need to try with next
// element
for (int i=pos+1; i<list.size(); i++) {
sumNext(list, i, nextSum, max, currentElement);
}
}
currentElement.remove(list.get(pos));
}
}
Will output:
max=10
2 3 5
4 6
max=13
2 5 6
2 11
3 4 6
Suppose I have a number 123. I need to see if I get all digits 1 through 9, including 0. The number 123 has three digits: 1,2, and 3. Then I multiply it by 2 and get 246 (I get digits 2, 4, 6). Then I multiply it by 3 and I get 369. I keep doing incremental multiplication until I get all digits.
My approach is the following:
public int digitProcessSystem(int N) {
String number = Integer.toString(N);
String [] arr = number.split("");
// List <Integer> arr2 = new ArrayList<>();
for (Integer i = 0; i < arr.length; i++) {
try {
arr2[i] = Integer.parseInt(arr[i]);
} catch (NumberFormatException e) {
}
}
count =0;
boolean contains = IntStream.of(arr2).anyMatch(x -> x == 1|| x==2 ||x == 3|| x==4|| x == 5|| x==6 ||x == 7|| x==8||x == 9|| x==0);
}
I really don't know how can I keep doing the boolean for digits that did not match in the first trail above because I will definitely get any one of the all digits in the above boolean search. How can I get that if some specific digits are present and some are not so that I can multiply the actual number to do the search for the digits that were not found in the first trial; just like the way I defined in the beginning.
You could wrap that into a while loop and include the numbers into a Set. Once the set has the size 10 all digits are present in the number. I´d also suggest to use a long instead of an int or you´ll be getting wrong results or run into an excpetion. Here´s some example code for this:
private static long digitProcessSystem(long N) {
long numberN = N;
String number = Long.toString(N);
// calculate 10 digits number here yet
if (number.length() < 10) {
// using the smallest possible number with each digit
// By using this number we are most likely allmost at the result
// This will increase the performance for small digits heavily.
long divider = 1023456789L / numberN;
numberN *= divider;
}
number = Long.toString(numberN);
String[] arr = number.split("");
Set<String> input = new HashSet<>(Arrays.asList(arr));
while(input.size() != 10){
// add N to number
numberN += N;
// Parse the new number
number = Long.toString(numberN);
// split
arr = number.split("");
// clear set
input.clear();
// Add the new numbers to the set. If it has the size 10 now the loop will stop and return the number.
input.addAll(Arrays.asList(arr));
};
return numberN;
}
public static void main(String[] args) {
System.out.println(digitProcessSystem(123));
}
output:
1023458769
I'm not sure what is your end goal. But you can use a HashSet and do something like this in order to achieve what you are trying to achieve:
public static void main (String[] args) throws Exception {
long number = 123L, counter = 1000000000L / number;
while(digitProcessSystem(number * counter++));
System.out.println("Number: " + number * (counter - 1));
}
public static boolean digitProcessSystem(long input) {
char[] arr = Long.toString(input).toCharArray();
Set<Character> set = new HashSet<>();
for (int i = 0; i < arr.length; i++) {
set.add(arr[i]);
}
return set.size() != 10;
}
Output:
Number: 1023458769
without using java language Facilities and hashset:
private static long digitProcessSystem(long N) {
long numberN = N;
String number = Long.toString(N);
String[] arr = number.split("");;
int arr2=new int[10];
int sum=0;
while(sum != 10){
sum=0;
// add N to number
numberN += N;
// Parse the new number
number = Long.toString(numberN);
// If it doesn´t have 10 digitis continue here yet
if(number.length() < 10) continue;
// split
arr = number.split("");
for(int i=0;i<arr.length;i++){
arr2[arr]=1;
}
for(int i=0;i<10;i++){
sum+=arr2[i];
}
};
return numberN;
}
Generally, if you want to process the characters of a String, don’t do it by splitting the string into substrings. Note that every CharSequence, including String, has the methods chars() and codepoints() allowing to process all characters as IntStream.
To check whether all digits from '0' to '9' are present, we can use chars() (don’t have to think about surrogate pairs) and do it straight-forward, map them to their actual number by subtracting '0', filter out all non-digits (just to be sure), then, map them to an int where the nth bit is set, so we can binary or them all together and check whether all of the lowest ten bits are set:
public static boolean hasAllDigits(String s) {
return s.length()>9 &&
s.chars().map(c -> c-'0').filter(c -> c>=0 && c<=9)
.map(c -> 1 << c).reduce(0, (a,b)->a|b) == 0b1111111111;
}
As a bonus, a length-check is prepended as a String must have at least ten characters to contain all ten digits, so we can short-cut if it hasn’t.
Now, I’m not sure about your actual task. If you just want to iterate until encountering a number having all digits, it’s quite simple:
long number=123;
for(long l = 1, end = Long.MAX_VALUE/number; l < end; l++) {
long candidate = number * l;
if(hasAllDigits(String.valueOf(candidate))) {
System.out.println("found: "+candidate);
return;
}
}
System.out.println("not found within the long range");
But if you want to know when you encountered all digits within the sequence of numbers, we have to adapt the test method and keep the bitset between the iterations:
public static int getDigits(String s) {
return s.chars().map(c -> c-'0').filter(c -> c>=0 && c<=9)
.map(c -> 1 << c).reduce(0, (a,b)->a|b);
}
long number=123;
int digits=0;
for(long l = 1, end = Long.MAX_VALUE/number; l < end; l++) {
long candidate=number * l;
int newDigits=digits | getDigits(String.valueOf(candidate));
if(newDigits != digits) {
System.out.printf("pos %10d: %10d%n", l, candidate);
digits=newDigits;
if(digits == 0b1111111111) {
System.out.println("encountered all digits");
break;
}
}
}
if(digits != 0b1111111111) {
System.out.println("did not encounter all digits within the long range");
}
This method will only print numbers of the sequence which have at least one digit not encountered before, so you can easily see which one contributed to the complete set and will see at most ten numbers of the sequence.
I need to find the smallest number which digit numbers product is equal to a given num.
import java.util.Scanner;
class timus_1014_2 {
public static void main(String[] args){
int[] arr = new int[10]; // eskan ban# chem imanum inchi a statik,
int prod = 1;
int j = 0;
Scanner in = new Scanner(System.in);
int n = in.nextInt();
for (int i = 2; i < 10; ++i){
if (n % i == 0) {
arr[j] = i;
j++;
}
}
prod = prod * arr[j];
System.out.print(prod);
}
}
Something is wrong with the logic, whats is the problem when I input 10 it should give 25 but it gives 0. Please give ideas of how to make a program find a number which digits product is a given num.
If I understood your problem correctly you need a number whose product of digits equals a number N. Since you asked for new algorithm , you can chck following code.
Logic:
Note : For number whose prime factors are less than 10
Get all factors from 9 -> 2
add to list
print in reverse or use stack instead of list
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Enter number");
int num = in.nextInt();
List<Integer> lst = new ArrayList<>();
for (int p = 9; p >= 2; p--) {
while (num % p == 0) {
num /= p;
lst.add(p);
}
}
String smallestNumber = "";
for (int i = lst.size() - 1; i >= 0; i--) {
smallestNumber = smallestNumber + lst.get(i);
}
System.out.println("Smallest number : " + smallestNumber);
}
}
Output :
Enter number
10
Smallest number : 25
Enter number
144
Smallest number : 289
Enter number
12
Smallest number : 26
I suggest you look at each error is fix it one by one. I also suggest you use an IDE which will show you the errors and you type and will help ensure you don't have an overwhelming number of errors and you can see if those error disappear based on your corrections.
BTW Often when you use an array for a short piece of code, it can often be eliminate as I suspect it can be removed in your case.
Static methods can not access non-static members of class.
In your case prod is member variable of class but not static. To fix the error , try to make prod as static.
private static int prod = 1;
I would prefer , to make it local variable if no other method is using it.
The problem here is you need to create an object of the particular class to call a particular method associated with it
import java.util.Scanner;
class DigPro {
static int[] arr = new int[10]; // eskan ban# chem imanum inchi a statik,
int prod = 1;
public static void main(String[] args){
Scanner in = new Scanner(System.in);
DigPro obj = new DigPro();
obj.prime(in.nextInt());
}
public void prime(int n){
for (int i = 1; i < 10; ++i){
for (int j = 0; j < 9; ++j) {
if (n % i == 0) {
arr[j] = i;
}
prod = prod * arr[j];
}
}
System.out.print(prod);
}
}
Here you need to create an object say obj of DigPro class and then call prime(int n) method with that object. Also your division is startint with zero which is changed to one
In above code you are increasing j after the assigning value to arr[j].You should do the following:-
prod = prod * arr[j-1];
Here it will multiply prod with last array updated. That is why you are getting zero. And for your another question find the smallest number which digit numbers product is equal to a given num has similar answer at this link.
Since this is actually a pretty interesting problem, I took the time to come up with a correct solution for all possible integer inputs.
import java.util.*;
public class Main{
public static void main(String[] args) {
System.out.println("Enter number:");
int number = new Scanner(System.in).nextInt();
Stack<String> factors = new Stack<>();
if(number==0){
factors.push("0");
}else if(number==1){
factors.push("1");
}else{
for(int f=9;f>1;f--){
while(number%f==0){
factors.push(Integer.toString(f));
number/=f;
}
}
}
if(number<0){
factors.push("-");
}
if(number>9){
System.out.println("This is impossible.");
}else{
System.out.println("Smallest Number:");
while(!factors.empty()) System.out.print(factors.pop());
}
}
}
I have to generate all variations without repetitions made of digits 0 - 9.
Length of them could be from 1 to 10. I really don't know how to solve it, especially how to avoid repetitions.
Example:
length of variations: 4
random variations: 9856, 8753, 1243, 1234 etc. (but not 9985 - contains repetition)
Can you please help me? Or can you give me the code?
The keyword to look for is permutation. There is an abundance of source code freely available that performs them.
As for keeping it repetition free I suggest a simple recursive approach: for each digit you have a choice of taking it into your variation or not, so your recursion counts through the digits and forks into two recursive calls, one in which the digit is included, one in which it is excluded. Then, after you reached the last digit each recursion essentially gives you a (unique, sorted) list of repetition-free digits. You can then create all possible permutations of this list and combine all of those permutations to achieve your final result.
(Same as duffymo said: I won't supply code for that)
Advanced note: the recursion is based on 0/1 (exclusion, inclusion) which can directly be translated to bits, hence, integer numbers. Therefore, in order to get all possible digit combinations without actually performing the recursion itself you could simply use all 10-bit integer numbers and iterate through them. Then interpret the numbers such that a set bit corresponds to including the digit in the list that needs to be permuted.
Here is my Java code. Feel free to ask if you don't understand. The main point here is:
sort again character array. for example: a1 a2 a3 b1 b2 b3 .... (a1 = a2 = a3)
generate permutation and always keep condition: index of a1 < index of a2 < index of a3 ...
import java.util.Arrays;
public class PermutationDup {
public void permutation(String s) {
char[] original = s.toCharArray();
Arrays.sort(original);
char[] clone = new char[s.length()];
boolean[] mark = new boolean[s.length()];
Arrays.fill(mark, false);
permute(original, clone, mark, 0, s.length());
}
private void permute(char[] original, char[] clone, boolean[] mark, int length, int n) {
if (length == n) {
System.out.println(clone);
return;
}
for (int i = 0; i < n; i++) {
if (mark[i] == true) continue;
// dont use this state. to keep order of duplicate character
if (i > 0 && original[i] == original[i-1] && mark[i-1] == false) continue;
mark[i] = true;
clone[length] = original[i];
permute(original, clone, mark, length+1, n);
mark[i] = false;
}
}
public static void main(String[] args) {
PermutationDup p = new PermutationDup();
p.permutation("abcab");
}
}
I have created the following code for generating permutations where ordering is important and with no repetition. It makes use of generics for permuting any type of object:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Permutations {
public static <T> Collection<List<T>> generatePermutationsNoRepetition(Set<T> availableNumbers) {
Collection<List<T>> permutations = new HashSet<>();
for (T number : availableNumbers) {
Set<T> numbers = new HashSet<>(availableNumbers);
numbers.remove(number);
if (!numbers.isEmpty()) {
Collection<List<T>> childPermutations = generatePermutationsNoRepetition(numbers);
for (List<T> childPermutation : childPermutations) {
List<T> permutation = new ArrayList<>();
permutation.add(number);
permutation.addAll(childPermutation);
permutations.add(permutation);
}
} else {
List<T> permutation = new ArrayList<>();
permutation.add(number);
permutations.add(permutation);
}
}
return permutations;
}
}
Imagine you had a magical function - given an array of digits, it will return you the correct permutations.
How can you use that function to produce a new list of permutations with just one extra digit?
e.g.,
if i gave you a function called permute_three(char[3] digits), and i tell you that it only works for digits 0, 1, 2, how can you write a function that can permute 0, 1, 2, 3, using the given permute_three function?
...
once you solved that, what do you notice? can you generalize it?
using Dollar it is simple:
#Test
public void generatePermutations() {
// digits is the string "0123456789"
String digits = $('0', '9').join();
// then generate 10 permutations
for (int i : $(10)) {
// shuffle, the cut (0, 4) in order to get a 4-char permutation
System.out.println($(digits).shuffle().slice(4));
}
}
The code for this is similar to the one without duplicates, with the addition of an if-else statement.Check this code
In the above code,Edit the for loop as follows
for (j = i; j <= n; j++)
{
if(a[i]!=a[j] && !is_duplicate(a,i,j))
{
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j));
}
else if(i!=j) {} // if no duplicate is present , do nothing
else permute(a,i+1,n); // skip the ith character
}
bool is_duplicate(int *a,int i,int j)
{
if a[i] is present between a[j]...a[i]
return 1;
otherwise
return 0;
}
worked for me
Permutation without repetition is based on theorem, that amount of results is factorial of count of elements (in this case numbers). In your case 10! is 10*9*8*7*6*5*4*3*2*1 = 3628800. The proof why it is exactly right is right solution for generation also.
Well so how. On first position i.e. from left you can have 10 numbers, on the second position you can have only 9 numbers, because one number is on the position on the left and we cannot repeat the same number etc. (the proof is done by mathematical induction).
So how to generate first ten results? According my knowledges, he simplest way is to use cyclic shift. It means the order of number shift to the left on one position (or right if you want) and the number which overflow to put on the empty place.
It means for first ten results:
10 9 8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1 10
8 7 6 5 4 3 2 1 10 9
7 6 5 4 3 2 1 10 9 8
6 5 4 3 2 1 10 9 8 7
5 4 3 2 1 10 9 8 7 6
...
The first line is basic sample, so it is the good idea to put it into set before generation. Advantage is, that in the next step you will have to solve the same problem to avoid undesirable duplicities.
In next step recursively rotate only 10-1 numbers 10-1 times etc.
It means for first 9 results in step two:
10 9 8 7 6 5 4 3 2 1
10 8 7 6 5 4 3 2 1 9
10 7 6 5 4 3 2 1 9 8
10 6 5 4 3 2 1 9 8 7
10 5 4 3 2 1 9 8 7 6
...
etc, notice, that first line is present from previous step, so it must not be added to generated set again.
Algorithm recursively doing exactly that, what is explained above. It is possible to generate all the 3628800 combinations for 10!, because number of nesting is the same as number of elements in array (it means in your case for 10 numbers it lingers about 5min. on my computer) and you need have enough memory if you want to keep all combinations in array.
There is solution.
package permutation;
/** Class for generation amount of combinations (factorial)
* !!! this is generate proper permutations without repeating and proper amount (počet) of rows !!!
*
* #author hariprasad
*/
public class TestForPermutationII {
private static final String BUMPER = "*";
private static int counter = 0;
private static int sumsum = 0;
// definitoin of array for generation
//int[] testsimple = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] testsimple = {1, 2, 3, 4, 5};
private int ELEMNUM = testsimple.length;
int[][] shuff;
private String gaps(int len) {
String addGap = "";
for(int i=0; i <len; i++)
addGap += " ";
return addGap;
}
/** Factorial computing */
private int fact(int num) {
if (num > 1) {
return num * fact(num - 1);
} else {
return 1;
}
}
/** Cyclic shift position to the left */
private int[] lShiftPos(int[] arr, int pos) {
int[] work = new int[ELEMNUM];
int offset = -1;
for (int jj = 0; jj < arr.length; jj++) {
if (jj < pos) {
work[jj] = arr[jj];
} else if (jj <= arr.length - 1) {
if (jj == pos) {
offset = arr[pos]; // last element
}
if (jj != (arr.length - 1)) {
work[jj] = arr[jj + 1];
} else {
work[jj] = offset;
}
}
}
return work;
}
private String printBuff(int[] buffer) {
String res = "";
for (int i= 0; i < buffer.length; i++) {
if (i == 0)
res += buffer[i];
else
res += ", " + buffer[i];
}
return res;
};
/** Recursive generator for arbitrary length of array */
private String permutationGenerator(int pos, int level) {
String ret = BUMPER;
int templen = counter;
int[] work = new int[ELEMNUM];
int locsumread = 0;
int locsumnew = 0;
//System.out.println("\nCalled level: " + level);
for (int i = 0; i <= templen; i++) {
work = shuff[i];
sumsum++;
locsumread++;
for (int ii = 0; ii < pos; ii++) {
counter++;
sumsum++;
locsumnew++;
work = lShiftPos(work, level); // deep copy
shuff[counter] = work;
}
}
System.out.println("locsumread, locsumnew: " + locsumread + ", " + locsumnew);
// if level == ELEMNUM-2, it means no another shift
if (level < ELEMNUM-2) {
ret = permutationGenerator(pos-1, level+1);
ret = "Level " + level + " end.";
//System.out.println(ret);
}
return ret;
}
public static void main(String[] argv) {
TestForPermutationII test = new TestForPermutationII();
counter = 0;
int len = test.testsimple.length;
int[] work = new int[len];
test.shuff = new int[test.fact(len)][];
//initial
test.shuff[counter] = test.testsimple;
work = test.testsimple; // shalow copy
test.shuff = new int[test.fact(len)][];
counter = 0;
test.shuff[counter] = test.testsimple;
test.permutationGenerator(len-1, 0);
for (int i = 0; i <= counter; i++) {
System.out.println(test.printBuff(test.shuff[i]));
}
System.out.println("Counter, cycles: " + counter + ", " + sumsum);
}
}
Intensity (number of cycles) of algorithm is sum of incomplete factorials of number of members. So there is overhang when partial set is again read to generate next subset, so intensity is:
n! + n!/2! + n!/3! + ... + n!/(n-2)! + n!(n-1)!
There is one solution which is not from mine, but it is very nice and sophisticated.
package permutations;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* #author Vladimir Hajek
*
*/
public class PermutationSimple {
private static final int MAX_NUMBER = 3;
Set<String> results = new HashSet<>(0);
/**
*
*/
public PermutationSimple() {
// TODO Auto-generated constructor stub
}
/**
* #param availableNumbers
* #return
*/
public static List<String> generatePermutations(Set<Integer> availableNumbers) {
List<String> permutations = new LinkedList<>();
for (Integer number : availableNumbers) {
Set<Integer> numbers = new HashSet<>(availableNumbers);
numbers.remove(number);
if (!numbers.isEmpty()) {
List<String> childPermutations = generatePermutations(numbers);
for (String childPermutation : childPermutations) {
String permutation = number + childPermutation;
permutations.add(permutation);
}
} else {
permutations.add(number.toString());
}
}
return permutations;
}
/**
* #param args
*/
public static void main(String[] args) {
Set<Integer> availableNumbers = new HashSet<>(0);
for (int i = 1; i <= MAX_NUMBER; i++) {
availableNumbers.add(i);
}
List<String> permutations = generatePermutations(availableNumbers);
for (String permutation : permutations) {
System.out.println(permutation);
}
}
}
I think, this is the excellent solution.
Brief helpful permutation indexing Knowledge
Create a method that generates the correct permutation, given an index value between {0 and N! -1} for "zero indexed" or {1 and N!} for "one indexed".
Create a second method containing a "for loop" where the lower bound is 1 and the upper bound is N!. eg.. "for (i; i <= N!; i++)" for every instance of the loop call the first method, passing i as the argument.
def find(alphabet, alpha_current, str, str_current, max_length, acc):
if (str_current == max_length):
acc.append(''.join(str))
return
for i in range(alpha_current, len(alphabet)):
str[str_current] = alphabet[i]
alphabet[i], alphabet[alpha_current] = alphabet[alpha_current], alphabet[i]
find(alphabet, alpha_current+1, str, str_current+1, max_length, acc)
alphabet[i], alphabet[alpha_current] = alphabet[alpha_current], alphabet[i]
return
max_length = 4
str = [' ' for i in range(max_length)]
acc = list()
find(list('absdef'), 0, str, 0, max_length, acc)
for i in range(len(acc)):
print(acc[i])
print(len(acc))