preventing redundant random numbers - java

I'm trying to get random numbers 0 - 499 in sets of 2 based on what the user inputs. For example 234 and 58, and thats one set, but the user may prompt that they wan 8 sets. Im trying to make sure that a redundant number doesnt show up, like 234 & 58, 12 & 444, 198 & 58. (58 showed up twice.)
The way im trying to prevent this is by putting the found numbers into an array and when i go around the next match im checking in the array to make sure they havent been used yet. Was just wondering what the best way of this would be. Like obviously on the first go around no numbers have been chosen yet so i dont need to check. but then the next go around what if i get a redundant? i will get numbers and then check the array, and if it is already in the array how do i go back and get new numbers? a do while loop maybe?
here is what im doing:
//now add the specified number of random connections
System.out.println();
System.out.println("new connection(s): ");
//array for keeping track of the new connections to prevent redundant add's
int redundant [] = new int[con*2];
for( int i = 1; i <= con; i++ ){
Random ran = new Random();
if( i == 1){
int ran1 = ran.nextInt(sWorld.length-1) + 1;
int ran2 = ran.nextInt(sWorld.length-1) + 1;
redundant[i - 1] = ran1;
redundant[i] = ran2;
System.out.println(" " + ran1 + " - " + ran2);
}
else{
int ran1 = ran.nextInt(sWorld.length-1) + 1;
int ran2 = ran.nextInt(sWorld.length-1) + 1;
//need help
}
thanks in advance!
EDIT. Going with a maethod below (using collections)
List<Integer> nums = new LinkedList<Integer>();
for( int i = 0; i <= 499; i++ ){
nums.add(i);
}
//shuffle the collection for more randomness
System.out.println();
System.out.println("new connection(s): ");
for (int x = 1; x <= con; x++){
Collections.shuffle(nums);
Random ran = new Random();
int r1 = nums.remove(ran.nextInt(nums));
int r2 = nums.remove(ran.nextInt(nums));
but having trouble getting the random numbers, any help?

Just fill a collection with all indices in the desired range (i.e. 0 to 499), and then use Collections.shuffle().

One way is to create a list of number from 0-499
List<Integer> nums = new LinkedList<Integer>();
for(int i=0; i<=499; i++) nums.add(i);
Then shuffle the the list
Collections.shuffle(nums);
Then each time you need a non-recurring random number between 0-499, just remove an element from the list
int x = nums.remove()

Use a while cycle and use an array. While your index is not out of scope generate two numbers. Add them to the array if they are not redundant and increase your index accordingly. If they are redundant, do nothing, the next iteration of the while cycle will generate two new numbers anyway.

Related

How to make random non-repeating numbers?

I made a code that could generate random numbers, but my issue is that sometimes it would repeat two or three numbers from time to time.
int winnum[] = new int[6];
System.out.print("Lotto winning numbers: ");
for(int i = 0; i < winnum.length; i++){
winnum[i] = 0 + (int)(Math.random() * 42);
System.out.print(winnum[i] + " ");
}
here is my code for generating random numbers
A fairly easy way to do this is to re-imagine this a little bit. Instead of 'generate a random number', think about a deck of cards. You don't 'generate random cards' - you generate (well, print) 52 cards in a specific order and then you randomize their order. Now you can draw cards off the top of the deck and they'll be random, but they cannot repeat.
Do the same thing: Make a list, fill it with all 42 numbers, then shuffle the list, then pull the top 6 numbers off of the list. Voila: Random - and without repetition.
var numbers = new ArrayList<Integer>();
for (int i = 0; i < 42; i++) numbers.add(i);
Collections.shuffle(numbers);
for (int i = 0; i < 6; i++) {
System.out.print(list.get(i) + " ");
}
Here is a real quick way using streams.
Random r = new Random();
r.ints(n,m) - generate a stream of random values between n and m-1 inclusive
distinct - ensure they are unique
limit(n) - limit to n
toArray - return as an array.
int [] result = r.ints(0,42).distinct().limit(6).toArray();
System.out.println(Arrays.toString(result));
prints something like
[37, 19, 28, 31, 15, 12]
You need to check whether the array contains the newly generated random number. If not, you add it, otherwise, keep generating random numbers until one that's not in the array is generated.
To check whether the number is found in the array, you can write the following function that takes the random integer, your array and returns a boolean:
boolean exists = false;
for (int n : winnum) {
if (n == randomInt) {
exists = true;
break;
}
} return exists;

How to know the fewest numbers we should add to get a full array

recently I met a question like this:
Assume you have an int N, and you also have an int[] and each element in this array can only be used once time. And we need to design an algorithm to get 1 to N by adding those numbers and finally return the least numbers we need to add.
For example:
N = 6, array is [1,3]
1 : we already have.
2 : we need to add it to the array.
3 : we can get it by doing 1 + 2.
4: 1 + 3.
5 : 2 + 3.
6 : 1 + 2 + 3.
So we just need to add 2 to our array and finally we return 1.
I am thinking of solving this by using DFS.
Do you have some better solutions? Thanks!
Here's an explanation for why the solution the OP posted works (the algorithm, briefly, is to traverse the sorted existing elements, keep an accumulating sum of the preceding existing elements and add an element to the array and sum if it does not exist and exceeds the current sum):
The loop tests in order each element that must be formed and sums the preceding elements. It alerts us if there is an element needed that's greater than the current sum. If you think about it, it's really simple! How could we make the element when we've already used all the preceding elements, which is what the sum represents!
In contrast, how do we know that all the intermediate elements will be able to be formed when the sum is larger than the current element? For example, consider n = 7, a = {}:
The function adds {1,2,4...}
So we are up to 4 and we know 1,2,3,4 are covered,
each can be formed from equal or lower numbers in the array.
At any point, m, in the traversal, we know for sure that
X0 + X1 ... + Xm make the largest number we can make, call it Y.
But we also know that we can make 1,2,3...Xm
Therefore, we can make Y-1, Y-2, Y-3...Y-Xm
(In this example: Xm = 4; Y = 1+2+4 = 7; Y-1 = 6; Y-2 = 5)
Q.E.D.
I don't know if this is a good solution or not:
I would create a second array (boolean array) remembering all numbers I can calculate.
Then I would write a method simulating the adding of a number to the array. (In your example the 1, 3 and 2 are added to the array).
The boolean array will be updated to always remember which values (numbers) can be calculated with the added numbers.
After calling the add method on the initial array values, you test for every Number x ( 1 <= x <= N ) if x can be calculated. If not call the add method for x.
since my explanation is no good I will add (untested) Java code:
static int[] arr = {3,5};
static int N = 20;
//An Array remembering which values can be calculated so far
static boolean[] canCalculate = new boolean[N];
//Calculate how many numbers must be added to the array ( Runtime O(N^2) )
public static int method(){
//Preperation (adding every given Number in the array)
for(int i=0; i<arr.length; i++){
addNumber(arr[i]);
}
//The number of elements added to the initial array
int result = 0;
//Adding (and counting) the missing numbers (Runtime O(N^2) )
for(int i=1; i<=N; i++){
if( !canCalculate[i-1] ){
addNumber(i);
result++;
}
}
return result;
}
//This Method is called whenever a new number is added to your array
//runtime O(N)
public static void addNumber( int number ){
System.out.println("Add Number: "+(number));
boolean[] newarray = new boolean[N];
newarray[number-1] = true;
//Test which values can be calculated after adding this number
//And update the array
for(int i=1; i<=N; i++){
if( canCalculate[i-1] ){
newarray[i-1] = true;
if( i + number <= N ){
newarray[i+number-1] = true;
}
}
}
canCalculate = newarray;
}
Edit: Tested the code and changed some errors (but rachel's solution seems to be better anyway)
It is a famous problem from dynamic programming. You can refer to complete solution here https://www.youtube.com/watch?v=s6FhG--P7z0
I just found a possible solution like this
public static int getNum(int n, int[] a) {
ArrayList<Integer> output = new ArrayList<Integer>();
Arrays.sort(a);
int sum = 0;
int i = 0;
while(true) {
if (i >= a.length || a[i] > sum + 1) {
output.add(sum + 1);
sum += sum + 1;
} else {
sum += a[i];
i++;
}
if (sum >= n) {
break;
}
}
return output.size();
};
And I test some cases and it looks correct.
But the one who write this didn't give us any hints and I am really confused with this one. Can anybody come up with some explanations ? Thanks!

Adding numbers to an array each loop

I made a quick program recently to have the computer guess a number you input. I was just using it to show a friend an example of a While loop. I decided I wish to make it more complicated but I'm not sure how to do it.
I wish to add each random guess to an array so that it doesn't guess the same number more than once.
Scanner scan = new Scanner (System.in); // Number to guess //
Random rand = new Random(); // Generates the guess //
int GuessNum = 0, RandGuess = 0;
System.out.println("Enter a number 1 - 100 for me to guess: ");
int input = scan.nextInt();
if (input >= 1 && input <= 100)
{
int MyGuess = rand.nextInt (100) + 1;
while ( MyGuess != input)
{
MyGuess = rand.nextInt (100) + 1;
GuessNum++;
}
System.out.println ("I guessed the number after " + GuessNum + " tries.");
}
You might want to use an ArrayList(A dynamically increasing array)
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(num);
If you want to see if that number is already added into the arraylist
if(list.contains(num))
{
System.out.println("You already tried " + num);
}
A Set is also considerably better option. It is the same as a ArrayList but doesn't allow duplicates.
HashSet<Integer> set = new HashSet<Integer>();
set.add(num);//returns true if the num was not inserted before else return false
if(!set.add(num))//set also has a contains method
{
System.out.println("You already entered " + num);
}
A Set is an appropriate container for that functionality. You would define it like this :
Set<Integer> previous = new HashSet<>();
And to get a random number that you haven't previously tried
while (previous.contains(MyGuess))
MyGuess = rand.nextInt(100) + 1;
previous.add(MyGuess);
This will get new random numbers from rand object until one is found that isn't in previous. Then that is added to previous for the next iteration.
Arrays in Java are of fixed size. Once you have allocated an array, adding elements is allowed only up to the number of elements that you have allocated upfront. This wouldn't be a big issue in your situation, because the values are limited to 100, but you have better alternatives:
Java library offers collections that grow dynamically. In your case a HashSet<Integer> would be a good choice:
HashSet can grow to an arbitrary size as you go
Checking HashSet for a number is a quick operation
Another solution would be to make an array of 101 booleans:
boolean[] seen = new boolean[101];
Now you can check if the number has been seen before by testing seen[myGuess] to be false, and set seen[myGuess] = true when you see a new number. This approach is also very fast. However, you need to keep track of how many available numbers you have, because the range from 1 to 100 will get exhausted after 100 guesses, so trying to generate an additional number would become an infinite loop.
Use a HashSet<Integer> to do this. The values in a Set are unique so this is an easy way to store the already guessed values.
The contains(...) method is how you find out if you've guessed this number before
A very simple example would be:
public static int[] randomArray(){
int number = Integer.parseInt(JOptionPane.showInputDialog("How many numbers would you like to save?: ")); //Get Number of numbers from user
int[] array = new int[number]; //Create the array with number of numbers (by User)
for(int counter = 0; counter < number; counter++){ //For loop to get a new input and output every time
int arrayString = (int) (Math.random() * 10);
array[counter] = arrayString;
System.out.println("Number " + (counter + 1) + " is: " + array[counter]); //Print out the number
}
return array;
}
This example adds numbers every time the loop repeats, just replace the random with the number you want.
The easiest way would be to add an ArrayList and just to check if the list contains the random value:
Ar first you make and new ArrayList:
ArrayList<Integer> myGuesses = new ArrayList();
The second step is to add the random value to the list:
ArrayList<Integer> myGuesses = new ArrayList();
Now you only have to check if if the List cotains the value bevore generating a new one and counting your trys:
if(myGuesses.contains(MyGuess))
{
//your code
}
I applied this to your code:
Scanner scan = new Scanner(System.in); // Number to guess //
Random rand = new Random(); // Generates the guess //
int GuessNum = 0, RandGuess = 0;
ArrayList<Integer> myGuesses = new ArrayList();
System.out.println("Enter a number 1 - 100 for me to guess: ");
int input = scan.nextInt();
if (input >= 1 && input <= 100) {
int MyGuess = rand.nextInt(100) + 1;
while (MyGuess != input) {
if(myGuesses.contains(MyGuess))
{
MyGuess = rand.nextInt(100) + 1;
GuessNum++;
myGuesses.add(MyGuess);
}
}
System.out.println("I guessed the number after " + GuessNum + " tries.");
}
I hope that helps!

How to generate 6 different random numbers in java

I want to generate 6 different random numbers by using Math.random and store them into an array.
How can I make sure that they are different? I know I need to use for-loop to check the array but how...
This is the range. I only need numbers between 1 and 49.
( 1 + (int) (Math.random() * 49) )
In Java 8:
final int[] ints = new Random().ints(1, 50).distinct().limit(6).toArray();
In Java 7:
public static void main(final String[] args) throws Exception {
final Random random = new Random();
final Set<Integer> intSet = new HashSet<>();
while (intSet.size() < 6) {
intSet.add(random.nextInt(49) + 1);
}
final int[] ints = new int[intSet.size()];
final Iterator<Integer> iter = intSet.iterator();
for (int i = 0; iter.hasNext(); ++i) {
ints[i] = iter.next();
}
System.out.println(Arrays.toString(ints));
}
Just a little messier. Not helped by the fact that it's pretty tedious to unbox the Set<Integer> into an int[].
It should be noted that this solution should be fine of the number of required values is significantly smaller than the range. As 1..49 is quite a lot larger than 6 you're fine. Otherwise performance rapidly degrades.
Create a list containing the numbers 1 to 49.
Create a random number x between 0 and the size of the list, take the number being at index x in the list, and remove it from the list.
Repeat the previous step 5 times. And you're done. Note that java.util.Random has a nextInt(int max) method that you should use instead of Math.random().
Note regarding performance: this solution has an advantage compared to the "try until you get 6 different numbers" various solutions: it runs in a O(n) time. It doesn't matter much for 6 unique numbers out of 50, but if you want to get 48 or 49 unique random numbers out of 50, you'll start seeing a difference, because you might have to generate many random numbers before getting one that isn't already in the set.
EDIT:
to reduce the cost induced by the removal of the elements in the list, you could instead simply replace the element at index x with the last element of the list (and at the second iteration, with the element at size - 2, etc.)
You can use a Set.
Set<Integer> s = new HashSet<>();
while(s.size() != 6){
s.add(1 + (int) (Math.random() * 49));
}
Integer[] arr = s.toArray(new Integer[s.size()]);
This is enough to do this in your case because the number of distinct random numbers is relatively small compared to the size of the range you generate them.
Otherwise I would go with #JBNizet approach.
Generate any 6 numbers (not necessarily different). Order them.
a1 <= a2 <= a3 <= a4 <= a5 <= a6
Now take these 6 numbers
a1 < a2 + 1 < a3 + 2 < a4 + 3 < a5 + 4 < a6 + 5
These 6 are different and random.
The idea of this construct comes from some combinatorial proofs.
Its advantage is that it's simple, fast, and deterministic.
I think the time complexity is O(count*log(count)).
I wonder if it can be improved.
import java.util.TreeMap;
public class Test005 {
public static void main(String[] args) {
int count = 6;
int min = 1;
int max = 49;
// random number mapped to the count of its occurrences
TreeMap<Integer, Integer> mp = new TreeMap<Integer, Integer>();
for (int i=0; i<count; i++){
int d = ( min + (int) (Math.random() * (max-count+1)) );
if (!mp.containsKey(d)){
mp.put(d, 0);
}
mp.put(d, mp.get(d) + 1);
}
// now ensure the output numbers are different
int j = 0;
for (int num : mp.keySet()){
int cnt = mp.get(num);
for (int i=0; i<cnt; i++){
System.out.println(num + j);
j++;
}
}
}
}
I've just came up with a small idea for Java 8-.
Set<Integer> set = new LinkedHashSet<>();
while(set.size() != 6)
set.add(rnd.nextInt(49) + 1);
Instead of checking that the array has no duplicates, you can use a bit more smartness while generating the numbers, such that uniqueness is enforced at the outset.
Create a boolean[] as long as your range (49 entries);
generate a random number from the full range;
put that number into your output array;
"cross out" the corresponding index in the boolean[];
now generate another random number, but curtail the range by one (now 48);
instead of directly using that number as output, scan your boolean[], counting all the non-crossed entries. Stop when you reach the count equal to the random number generated in step 5. The number corresponding to that entry is your output number;
go to step 4.
in your case n=6
public static int[] chooseAny(int n){
int[] lottery = new int[n];
int[] chooseFrom = new int[49];
for(int i=1 ; i <= 49 ; i++)
chooseFrom[i-1] = i;
Random rand = new Random();
int N = 49;
int index;
for(int i=0 ; i < n ; i++){
//pick random index
index = rand.nextInt(N);
lottery[i] = chooseFrom[index];
chooseFrom[index] = chooseFrom[N-1];
N--;
}
return lottery;
}
Just keep generating numbers and adding them to the array as long as they are unique; psuedocode:
num = genNextRand()
For (array length)
If (num not in array)
addToArray()
Repeat while length not equal 6
Create a variable last; initialize it to 0.
Next, in a loop x from 0 to 5, create a random number between last+1 and 49-6+x. Store this number in a list, and set last to the number generated this way.
You will end up with an ordered list of 6 random numbers in the range of 1..49 with no repeats.
That code generate numbers from 6 to 0 and save in ArrayList.
If generated number was duplicated the program generate numbers again.
If generated number is different that number is added.
Code:
private ArrayList<Integer> arraylist = new ArrayList<Integer>();
private Random rand = new Random();
public void insertNumber() {
while (true) {
int i = generateNumber();
if(!isGenerateNumberExists(i)){
addNumber(i);
break;
}
}
}
//Generate numbers
private int generateNumber() {
return rand.nextInt(6);
}
//Confirm if that number exists
private boolean isGenerateNumberExists(int y) {
for (int num : arraylist) {
if (num == y) {
return true;
}
}
return false;
}
//Add number to arrayList
private void addNumber(int x) {
arraylist.add(x);
}

Issue with randomize method

I have a method that is not working properly.
The method is supposed to sort a set of numbers from 1 to 20 randomly (each number
must appear just once).
My issue here is that when I run the program, some numbers are repeated several times.
The code is the following:
public static int randomize(int index) {
//This array will hold the 20 numbers.
int[] randomIndex = new int[20];
Random ranNum = new Random();
for (int x = 0; x<20; x++) {
int temp;
//The number is generated randomly and saved in temp.
temp = ranNum.nextInt(20);
//This loop skips the first index.
if (x != 0){
/*Here, the loop is supposed to compare a generated number with
the previous one*/
for (int y = 1; y<=x; y++) {
while(temp == randomIndex[x-y] ) {
/*If the while loop finds that temp variable matches any previous
number it will generate another random number for it until it finds
no matches.*/
temp = ranNum.nextInt(20);
}
}
}
/*Once no match has been found for temp, the number is assigned to an index,
and the loop is executed with a x variable increment.
randomIndex[x] = temp;
}
//Finally the array with the set of random numbers is sent to the main function.
return randomIndex[index];
}
And I got the following output:
19, 19, 5, 16, 6, 2, 18, 1, 15, 1, 5, 19, 11, 4, 18, 0, 5, 18, 10.
So now I have no idea what to do. :C
When you use Random.nextInt(), there's no guarantee that the numbers generated are unique.
You should generate numbers from 1 to 20 first, then shuffle the numbers. Now the question is changed to "How to shuffle the numbers randomly?"
Perhaps you can refer the implementation of JDK Collections.shuffle().
The algorithm for shuffling the numbers are simple:
Pick first element in the array and swap it with a number at random position.
Repeat step 1 until the last element.
You can avoid it by using something like this:
final Random random = new Random();
final HashSet<Integer> integers = new HashSet<>();
while(integers.size() < 20) {
integers.add(random.nextInt(20));
}
System.out.println(integers);
It looks like you're trying to generate your random numbers by rejection -- that is, by comparing each random number with all previously accepted numbers, and re-generating new ones until you find one that is is different from all of them.
As others have mentioned, it would be far more efficient to generate the numbers from 1 to 20, and shuffle them with a random permutation. However, if implemented correctly, your approach should work... eventually.
A random shuffle implementation might look something like this:
for(int i=0; i<20; i++) { // index goes from 0..19
randomIndex[i] = i + 1; // value goes from 1..20
}
for(int i=0; i<20; i++) {
int j = i + ranNum.nextInt(20 - i); // choose random j from i <= j < 20
int temp = randomIndex[i]; // swap elements i and j
randomIndex[i] = randimIndex[j];
randomIndex[j] = temp;
}
The are two reasons why your posted code generates duplicates. First, when you reject a candidate random number and re-generate a new one, you need to compare it against all existing numbers, restarting you inner (y) loop from the beginning. Your existing code doesn't do that.
Second, I believe that the new Random() constructor generates a different seed each time it is called. If so, your randomize() function is generating a completely different random list each time, and returning the selected index from it. In any case, it makes more sense to return the entire array, instead.
I edited your function for generate array from 1 to 20:
public static int[] randomize() {
int[] randomIndex = new int[20];
Random ranNum = new Random();
boolean isAlreadyIn;
boolean isZero;
int x = 0;
while (x < 20) {
isAlreadyIn = false;
isZero = false;
int temp;
temp = ranNum.nextInt(21);
for(int i = 0; i < randomIndex.length; i++){
if(temp == 0)
isZero = true;
if(temp == randomIndex[i])
isAlreadyIn = true;
}
if (!isZero && !isAlreadyIn){
randomIndex[x] = temp;
x++;
}
}
return randomIndex;
}
hope it will be helpful.

Categories