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))
Related
I want to generate 4 random numbers and they can't have repeated digits.
For instance 4567, (it doesn't have a repeated value like 4557).
I want them to be random.
Is there any way to achieve this?
I'm obsessed with streams nowadays. But streams are pretty slow. To show the slowness I wrote following main method. "generateWithLoop" method covers #WJS's answer.
public static void main(String[] args) {
long nanoStart = System.nanoTime();
generateWithStreams();
long nanoEnd = System.nanoTime();
System.out.println("Elapsed time with Streams : " + (nanoEnd - nanoStart) + " nano seconds");
nanoStart = System.nanoTime();
generateWithLoop();
nanoEnd = System.nanoTime();
System.out.println("Elapsed time with Loop : " + (nanoEnd - nanoStart) + " nano seconds");
}
Console output :
Elapsed time with Streams : 81367089 nano seconds
Elapsed time with Loop : 75093 nano seconds
With stream :
public static void generateWithStreams() {
List<Integer> orderedList = getOrderedList();
for (int i = 0; i < 4; i++) {
List<Integer> shuffledList = getShuffledList(orderedList);
System.out.println(get4DigitNumber(shuffledList));
}
}
public static List<Integer> getOrderedList() {
return IntStream.range(0, 10).boxed().collect(Collectors.toList());
}
public static List<Integer> getShuffledList(List<Integer> list) {
return list.stream().sorted((o1, o2) -> ThreadLocalRandom.current().nextInt(-1, 2)).collect(Collectors.toList());
}
public static Integer get4DigitNumber(List<Integer> shuffledList) {
final Integer LIMIT = shuffledList.get(0).equals(0) ? 5 : 4;
return shuffledList.stream().limit(LIMIT).reduce(0, (sum, current) -> sum * 10 + current);
}
With loop :
public static void generateWithLoop() {
Random r = new Random();
for (int k = 0; k < 4; k++) {
int val = gen(r);
System.out.println(val);
}
}
static int[] base = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public static int gen(Random r) {
int val = 0;
int s = 10;
for (int i = 0; i < 4; i++) {
int n = r.nextInt(s);
val = val * 10 + base[n];
int save = base[n];
base[n] = base[--s];
base[s] = save;
}
return val < 1000 ? val * 10 + base[r.nextInt(s)] : val;
}
This will generate 4 digit random numbers with no repeating digits.
It works by generating 4 unique digits in the same fashion that one might shuffle a deck of cards in a computer game. It then simply builds up the four digit number by multiplication and addition.
If the number is less than 1000, then that means a 0 was used and was at the beginning. So just choose another digit to adjust.
Random r = new Random();
for (int k = 0; k < 10; k++) {
int val = gen(r);
System.out.println(val);
}
static int[] base = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public static int gen(Random r) {
int val = 0;
int s=10;
for (int i = 0; i < 4; i++) {
int n = r.nextInt(s);
val = val * 10 + base[n];
int save = base[n];
base[n] = base[--s];
base[s] = save;
}
return val < 1000 ? val * 10 + base[r.nextInt(s)] : val;
}
Here is a more straightforward way of doing it. The philosophy is the same as above. It may not be quite as efficient as the previous due to the shuffling of all the digits.
// generate four digit numbers that have distinct digits.
List<Integer> digits = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
Collections.shuffle(digits);
// now just use the first four of the shuffled list
if (digits.get(0) == 0) {
// for a 4 digit number, first digit can't be zero
// so choose another.
digits.set(0, digits.get(4));
}
// now use simple arithmetic to create the four digit number.
int n = 0;
for (int d : digits.subList(0,4)) {
n = n * 10 + d;
}
System.out.println(n);
public static void main(String[] args) {
List<Integer> list= new ArrayList<>();
for(int j = 0; j < 10; j++){
list.add(j);
}
Collections.shuffle(list);
String randomDigit= "";
for(int j = 0; j < 4; j++){
randomDigit+= list.get(j).toString();
}
System.out.println(randomDigit);
}
This is converting the string to int. But this will work you can use it.
Steps:
Create a List that will hold each individual number of the generated
4-digit number
Generate a random number for the units place between 1 and 9, and put it in the list
Create a loop to generate a random number between 0 and 9 for the
ten's place until the last place; and each time, put the random
number into your list. examine the number for each iteration that is not contained in your list
Eventually the size of the list is now 4; combine these 4 individuals into a String, and convert to Integer.
List<Integer> myNumber = new ArrayList<Integer>();
Random r = new Random();
// Generate a random number between 1 and 9 for units place
myNumber.add(r.nextInt(9) + 1);// adding 1 to avoid 0 in the units place
// Generate a random number between 0 and 9 for 10's and upcoming places
do {
Integer num = r.nextInt(10);
// Check the list doesn't contain that number
if (!myNumber.contains(num)) {
myNumber.add(num);
}
}while (myNumber.size() < 4);
StringBuilder numStr = new StringBuilder();
for (int i = 0; i < myNumber.size(); i++)
numStr.append(myNumber.get(i));
System.out.println(Integer.parseInt(numStr.toString()));
A solution using stream and Lambdas from Java-8 onwards:
public static void main(String[] args) {
Map<String, String> collect = IntStream.rangeClosed(1, 9).boxed()
.flatMap(x -> IntStream.rangeClosed(0, 9).boxed()
.flatMap(y -> IntStream.rangeClosed(0, 9).boxed()
.flatMap(z -> IntStream.rangeClosed(0, 9).boxed()
.flatMap(w -> IntStream.rangeClosed(1, 9).boxed().map(s -> s.toString()).filter(e -> noneRepete(x, y, z, w))
.map(k -> x.toString() + y.toString() + z.toString() + w.toString())))))
.collect(Collectors.toMap(Function.identity(), s -> s, (a, b) -> a));
collect.keySet().forEach(System.out::println);
}
public static boolean noneRepete(Integer a, Integer b, Integer c, Integer d) {
if (! a.equals(b) && ! a.equals(c) && ! a.equals(d) && a !=0) {
if (! b.equals(c) && ! b.equals(d)) {
return ! c.equals(d);
}
}
return false;
}
Explanation:
Here we are flattening the stream of Integers from 1 to 9(first digit cannot be 0).
while in further we are flattening stream of Integers from 0 to 9.
The above process goes 2 more time thus making it a four digit, we are having a custom filter which is making sure that all four digits are unique.
At last we are collecting them as keys and values making sure the digits are unique and key itself in a map is unique.
I'm doing a coding challenge online where I'm supposed to write a class that takes in a positive parameter ("num") and returns its multiplicative persistence. This is the number of times you must multiply the digits in "num" until you reach a single digit.
For example, the multiplicative persistence of 39 = 3. This is because:
3 * 9 = 27
2 * 7 = 14
1 * 4 = 4
This is the whole program so far:
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
public class Persist {
public static void main(String[] args) {
persistence(39);
}
public static int persistence(long num) {
int persistenceValue = 0;
List<Long> digitList = new ArrayList<Long>();
long lastDigit;
//Resolves if num is single digit
if (num <= 9) {
return 0;
}
//Takes each digit of number and stores it to digitList (backwards)
while (num > 0) {
lastDigit = (num % 10);
digitList.add(lastDigit);
num = num / 10;
}
//Takes each digit in digitList and stores it in array in correct order
for (Long d : digitList) {
Long[] currentDigitArray = new Long[digitList.size()];
for (int i = 0; i < currentDigitArray.length; i++) {
currentDigitArray[currentDigitArray.length - i] = d;
}
persistenceValue = currentDigitArray.length;
while (persistenceValue > 1) {
List<Long> productList = multiplyDigits(currentDigitArray);
persistenceValue++;
}
}
return persistenceValue;
}
public static List multiplyDigits(Long[] currentDigitArray) {
//multiplies each digit
List<Long> productList = new ArrayList<Long>();
for (int i = 0; i < currentDigitArray.length; i++) {
Long product = currentDigitArray[i] * currentDigitArray[i + 1];
productList.add(product);
}
return productList;
}
}
I keep running into an array out of bounds exception for the for loop on line 52:
//Takes each digit in digitList and stores it in an array
for (Long d : digitList) {
Long[] currentDigitArray = new Long[digitList.size()];
for (int i = 0; i < currentDigitArray.length; i++) {
currentDigitArray[currentDigitArray.length - i] = d;
// ^ exception is thrown here ^
}
So obviously I looked this up on Google like a good stack overflow user. An array-index out of bounds exception is a Java exception thrown due to the fact that the program is trying to access an element at a position that is outside an array limit, hence the words "Out of bounds."
The problem is that I have no idea how big that array is going to be up front because it's all going to depend on how many digits are passed in by the user. I hard coded 39, but eventually I want the user to be able to put in as many as they want.
So how else would I takes each digit in digitList and store it in array?
This part has been resolved, but now I have a similar problem on line 78:
public static List multiplyDigits(Long[] currentDigitArray) {
//multiplies each digit
List<Long> productList = new ArrayList<Long>();
for (int i = 0; i < currentDigitArray.length; i++) {
Long product = currentDigitArray[i] * currentDigitArray[i + 1];
//^This line here
productList.add(product);
}
return productList;
}
I feel like this is a very similar problem, but don't quite know how to fix it.
This assignment
currentDigitArray[currentDigitArray.length - i] = d;
should be
currentDigitArray[currentDigitArray.length - 1 - i] = d;
to avoid the problem.
With this said, you can avoid arrays entirely by performing multiplication as you go. Recall that the order in which you do multiplication does not change the result. Therefore, you can start multiplication from the back of the number, and arrive at the same solution.
Arrays are zero-indexed, so currentDigitArray.length is always going to be out of bounds. In fact, because of the additive identity property, currentDigitArray.length - i is going to be currentDigitArray.length when i is 0. To fix this, just subtract an extra 1 in your index calculation:
currentDigitArray[currentDigitArray.length - i - 1] = d;
For your second problem, you iterate one element too many, and you need to stop one element earlier:
for (int i = 0; i < currentDigitArray.length - 1; i++) {
I would like to know if there is any way to count like this:
base of each position:
4 2 3
counter values:
000--invalid - exception, always a non zero digit must be there
001
002
010
011
012
100
101--invalid : disconnected digits
102--invalid : disconnected digits
110
111
112
200
201--invalid : disconnected digits
202--invalid : disconnected digits
210
211
212
300
301--invalid : disconnected digits
302--invalid : disconnected digits
310
311
312
The idea is if non-zero digits are separated by zero, then leave that formation out. That means values like 101, 201 are invalid.
talking about decimal counting system for example (max: 9999), numbers like 1001, or 9010 will not be produced.
I came up with counting and then converting to each base, (in my first example, the bases would be 4.2.3 and for the 9999 example it would be 10.10.10.10) however, there are certain numbers of all numbers that they will be valid.
for example:
4.2.3: 17 out of 4*2*3 (or 24) will be valid
4.2.2.4: 30 out of 4*2*2*4 (or 64) will be valid
10.10.10.10: 8298 out of 10*10*10*10 (or 10000) will be valid.
as positions goes up, the more computation I need to perform.
What is your idea about a fast counter that can produce such numbers?
a simple solution as I mentioned would be count and convert, and then do a post process on generated numbers, but what is the optimized solution for this?
here is my code:
/**
* Author: Soleyman Pasban
* Date: Apr 6, 2016
*/
package PC;
public class DigitTest {
public static void main(String[] test) {
//int[] base = new int[]{4, 2, 3};
int[] base = new int[]{4, 2, 2, 4};
//int[] base = new int[]{10,10,10,10};
int valid = 0;
int total = 1;
for (int i = 0; i < base.length; i++) {
total *= base[i];
}
for (int i = 1; i < total; i++) {
int number = i;
int bi = base.length - 1;
String str = "";
while (bi >= 0) {
str = number % base[bi] + str;
number = number / base[bi];
bi--;
}
boolean pass = true;
boolean allowNonZero = true;
for (int j = 1; j < base.length; j++) {
if (str.charAt(j - 1) == '0' && str.charAt(j) != '0') {
//for the first case ...0* it should filter the cases
//I bypass it once by this, else the number must mark invalid
if (allowNonZero == false) {
pass = false;
}
allowNonZero = false;
}
//once see a zero, no none-zero must be appear
if (str.charAt(j - 1) != '0') {
allowNonZero = false;
}
}
if (pass) {
valid++;
} else {
str += " - invalid";
}
System.out.println(str);
}
System.out.println();
System.out.println("Valid: " + valid);
System.out.println("Total: " + total);
}
}
My question is if there is a way to keep the above algorithm simple. for a 16 digits like 4.8.7.2.2.3.2.2.4.2.7.4.2.3.2.2 (this is an example to show that it must work with any base) the amount of calculation, creating string variables and other stuff I think will be inefficient!
for an example if a number start with like 9010*********1 then this number is wrong from the beginning and counting the rest will be meaningless.
Is there any other solution for this problem? I would like to see if I can just produce the valid numbers by this.
Thanks
It's actually fairly simple. You start by creating a char[] of '0' characters for the appropriate length.
You then increment the last digit, and rollover when necessary. The updated array is then the next value, and you create the result using new String(buf).
Now, the trick is that when you roll over, you set the digit back to 0, and move one position to the left, and increment that. But, you remember how far you had to go left during chained rollovers, because you must increment the left-most zero on the next iteration, in order to prevent "disconnected digits".
Example:
1999
2000 <-- rollover, remember that second digit must be incremented next
2100 <-- now remember that third digit must be incremented next
2110 <-- now remember that forth digit must be incremented next
2111 <-- normal increment
2112 <-- normal increment
Since a weird counter like this is best if reusable, here is a class implementing this logic, including validation:
public final class WeirdCounter {
private int[] bases;
private char[] buf;
private int idx;
public WeirdCounter(int ... bases) {
if (bases.length == 0)
throw new IllegalArgumentException("No bases");
for (int base : bases)
if (base < 1 || base > 10)
throw new IllegalArgumentException("Invalid base:" + base);
this.bases = bases.clone();
this.buf = new char[bases.length];
Arrays.fill(this.buf, '0');
this.idx = this.buf.length - 1;
}
public String next() {
while (this.idx >= 0) {
char digit = this.buf[this.idx];
if (++digit < '0' + this.bases[this.idx]) {
this.buf[this.idx] = digit;
if (this.idx < this.buf.length - 1)
this.idx++;
return new String(this.buf);
}
this.buf[this.idx--] = '0';
}
return null;
}
}
This is very fast and easy to use:
WeirdCounter counter = new WeirdCounter(4,2,3);
for (String val; (val = counter.next()) != null; )
System.out.println(val);
OUTPUT
001
002
010
011
012
100
110
111
112
200
210
211
212
300
310
311
312
Note that the 16-digit example you gave (4.8.7.2.1.3...4.6.7.9.10...3.1.1) makes no sense. What does ... mean? Also, a base of 1 means that the digit can only ever be 0.
So, assuming that . means 1, the code will work. When a rollover crosses any such base-1 value, all digit to the right must stay 0.
Partial output using new WeirdCounter(4,8,7,2,1,3,1,4,6,7,9,10,1,3,1,1):
...
0000000356870000
0000000356880000
0000000356890000
0000010000000000
0000020000000000
0001000000000000
0010000000000000
0011000000000000
0020000000000000
0021000000000000
0030000000000000
0031000000000000
0040000000000000
0041000000000000
0050000000000000
0051000000000000
0060000000000000
0061000000000000
0100000000000000
0110000000000000
0111000000000000
...
Still, code is very, very fast, because when it tries to increment 0001000000000000, it knows to increment the first zero after the 1, so it immediate rolls over the base-1 digit and then increments the 1 digit to 2 instead, without even looking at the those other 0 digits.
public class Digits {
// make constructor or something
int[] base = new int[]{4, 2, 3};
int[] cur = new int[]{0, 0, 0};
public void find(int i, boolean hasNonZero) {
if (i == base.length) {
if (!hasNonZero) {
return; // all zeroes corner case
}
// output
for (int j = 0; j < base.length; j++) {
System.out.print(cur[j]);
}
System.out.println();
return;
}
for (int v = 0; v < base[i]; v++) { // each digit at position
if (hasNonZero && v != 0 && cur[i - 1] == 0) { // disconnected non zeroes
continue;
}
cur[i] = v;
find(i + 1, hasNonZero || v != 0); // next position
}
}
public static void main(String[] args) {
(new Digits()).find(0, false);
}
}
Simple recursion like this.
You can calculate the count without generating any numbers. Here's a simple O(n^3) solution to demonstrate the idea. It can probably be improved further.
public class DigitTest {
public static void main(String[] args) {
countWeirdNumbers(4, 2, 3);
countWeirdNumbers(4, 2, 2, 4);
countWeirdNumbers(10, 10, 10, 10);
}
public static void countWeirdNumbers(int... bases) {
long count = 0;
for (int start = 0; start < bases.length; start++) {
for (int end = start; end < bases.length; end++) {
int thisCount = 1;
for (int i = start; i <= end; i++) {
thisCount *= bases[i] - 1;
}
count += thisCount;
}
}
System.out.println(count);
}
}
The idea is that you're simply counting how many numbers don't have any zeroes in between the first and last nonzero digits. So iterate over all the possible positions of those two digits and count the possibilities for the digits in that range. Each digit has b-1 possibilities where b is the base at that position because 0 isn't allowed.
Here's a super-fast way that doesn't generate any invalid numbers. Just change the initializers for maxdigits and current for different base sequences.
It works by directly incrementing the previous number, so you can make an iterator out of it if you like.
This is good pattern to remember for generating a wide variety of different kinds of sequences in lexical order:
Given the "current item", you can always make the next item with these 2 steps:
Increment the rightmost character that can be greater than the corresponding character in the current item. This works because the next item must be greater, and given that must share the longest possible prefix in common with the current item. Then
Set the remaining characters to the lowest possible value, because otherwise you'd be skipping some.
These steps make it pretty easy to generate your sequence, and indeed a whole lot of other lexically ordered sequences.
public static void main (String[] args) throws java.lang.Exception
{
char[] maxdigits = "312".toCharArray();
char[] current = "001".toCharArray();
for (;;)
{
System.out.println(new String(current));
//each time we add 1, one digit is incremented by one,
//and all the lower-place digits are set to the least possible
//value
//Step 1 - find the position of digit to increment
boolean sawNonZero=false;
int incpos;
for(incpos = current.length-1; incpos>=0; --incpos)
{
if (current[incpos]=='0')
{
if (sawNonZero || current[incpos-1]!='0')
{
//can increment a leading zero or the first trailing zero
break;
}
//incrementing this one would create a zero gap
}
else
{
sawNonZero = true;
if (current[incpos]<maxdigits[incpos])
{
//can increment a digit that is less than max
break;
}
}
}
if (incpos<0)
{
break; //done
}
current[incpos]++;
//Step 2 - set the remaining digits to 0
for (incpos+=1; incpos<current.length; ++incpos)
{
current[incpos]='0';
}
}
}
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;}
Write a program that reads a sequence of integers into an array and that computes the alternating sum of all elements in the array. For example, if the program is executed with the input data
1 4 9 16 9 7 4 9 11
then it computes
1 - 4 + 9 - 16 + 9 - 7 + 4 - 9 + 11 = - 2
I have below code so far:
import java.util.Arrays;
/**
This class computes the alternating sum
of a set of data values.
*/
public class DataSet
{
private double[] data;
private int dataSize;
/**
Constructs an empty data set.
*/
public DataSet()
{
final int DATA_LENGTH = 100;
data = new double[DATA_LENGTH];
dataSize = 0;
}
/**
Adds a data value to the data set.
#param x a data value
*/
public void add(double x)
{
if (dataSize == data.length)
data = Arrays.copyOf(data, 2 * data.length);
data[dataSize] = x;
dataSize++;
}
/**
Gets the alternating sum of the added data.
#return sum the sum of the alternating data or 0 if no data has been added
*/
public double alternatingSum()
{
. . .
}
}
I have to use the following class as the tester class:
/**
This program calculates an alternating sum.
*/
public class AlternatingSumTester
{
public static void main(String[] args)
{
DataSet data = new DataSet();
data.add(1);
data.add(4);
data.add(9);
data.add(16);
data.add(9);
data.add(7);
data.add(4);
data.add(9);
data.add(11);
double sum = data.alternatingSum();
System.out.println("Alternating Sum: " + sum);
System.out.println("Expected: -2.0");
}
}
I implemented the method alternatingSum for you:
public double alternatingSum() {
double alternatingSum = 0;
if(data != null || dataSize > 0) {
for(int i = 0; i < dataSize; i = i + 2) {
alternatingSum += data[i];
}
for(int i = 1; i < dataSize; i = i + 2) {
alternatingSum -= data[i];
}
}
return alternatingSum;
}
I would use this simple logic to achieve the goal. First add all the odd numbers in the array. Then add all the even numbers from the same. Now subtract the both values n you will get your answer. Hope this helps.
I would solve this using a for loop and a boolean flag:
set flag to false
set sum to zero
for alle elements in array
if flag is set
add to sum
else
subtract from sum
When loop is done you have your sum.
int[] a = {50, 60, 60, 45, 70};
int sum = IntStream.range(0, a.length).filter(i -> i % 2 == 0).map(i -> a[i]).sum()
- IntStream.range(0, a.length).filter(i -> i % 2 == 1).map(i -> a[i]).sum();
System.out.println("Sum= " + sum);
I did this using stream, first I used Intstream, then filter out the even indexes and get the mapped the value and added them, and did the same for odd indexes as well, then subtracted it.
If You have 4 numbers, for example a[]={1, 3, 5, 6}, there are several cases:
operation:
+ + +
+ + -
+ - +
+ - -
- + +
- + -
- - +
- - -
In your case "operation" will be only + - +
use array with this symbols and calculate your result.
int k=a[0];
for(int i = 1; i<= 3; i++){
if(operation[i-1]=="+".charAt(0))
{k=k+a[i];}
etc...
}
It's not hard :)
good luck.