Generating random numbers in a particular range - java

I am trying to generate n random numbers between 0-31 in my Android code.
Below is the code that I am using:
int max_range = 31;
SecureRandom secureRandom = new SecureRandom();
int[] digestCodeIndicesArr = new int[indices_length];
int i = 0, random_temp = 0;
while (i != indices_length-1) {
random_temp = secureRandom.nextInt(max_range);
if (!Arrays.asList(digestCodeIndicesArr).contains(random_temp)) {
digestCodeIndicesArr[i] = random_temp;
i++;
}
}
indices_length is the number of random numbers that I need. It's generally 6,7 or 9. But when I print the generated array, I generally end up seeing duplicates. Can someone point out the mistake I am making. I have added the below line of code to filter out random duplicates:
if (!Arrays.asList(digestCodeIndicesArr).contains(random_temp))
Thanks in advance!

Arrays.asList(digestCodeIndicesArr) does not produce a List<Integer> with size() == digestCodeIndicesArr.length.
It produces a List<int[]> with size() == 1, where first (and only) element is the array.
As such, it will never contain random_temp, so ! contains() is always true.
It is bad for performance to constantly create a list and perform a sequential search to check for duplicates. Use a Set instead, that you maintain in parallel with the array, or use a LinkedHashSet first, then convert to array.
Anyway, this explains why your code wasn't working. The duplicate link that Tunaki had provided and the duplicate link I provided in comment, explains how to actually do what you were trying to do.

You need to change:
int[] digestCodeIndicesArr = new int[indices_length];
to:
Integer[] digestCodeIndicesArr = new Integer[indices_length];
because Arrays.asList(digestCodeIndicesArr) is List<int[]>, and not what you thought probably (List<int> or List<Integer> I guess).

Related

Combination Java Performance

I want to use this function with a large amount of possibility like 700 integer but the function make too much time to execute. Does someone have an idea to increase the performance? Thank you :)
public static Set<Set<Integer>> combinations(List<Integer> groupSize, int k) {
Set<Set<Integer>> allCombos = new HashSet<Set<Integer>> ();
// base cases for recursion
if (k == 0) {
// There is only one combination of size 0, the empty team.
allCombos.add(new HashSet<Integer>());
return allCombos;
}
if (k > groupSize.size()) {
// There can be no teams with size larger than the group size,
// so return allCombos without putting any teams in it.
return allCombos;
}
// Create a copy of the group with one item removed.
List<Integer> groupWithoutX = new ArrayList<Integer> (groupSize);
Integer x = groupWithoutX.remove(groupWithoutX.size() - 1);
Set<Set<Integer>> combosWithoutX = combinations(groupWithoutX, k);
Set<Set<Integer>> combosWithX = combinations(groupWithoutX, k - 1);
for (Set<Integer> combo : combosWithX) {
combo.add(x);
}
allCombos.addAll(combosWithoutX);
allCombos.addAll(combosWithX);
return allCombos;
}
What features of Set are you going to need to use on the returned value?
If you only need some of them - perhaps just iterator() or contains(...) - then you could consider returning an Iterator which calculates the combinations on the fly.
There's an interesting mechanism to generate the nth combination of a lexicographically ordered set here.
Other data structure. You could try a BitSet instead of the Set<Integer>. If the integer values have a wild range (negative, larger gaps), use an index in groupSize.
Using indices instead of integer values has other advantages: all subsets as bits can be done in a for-loop (BigInteger as set).
No data. Or make an iterator (Stream) of all combinations to repeatedly apply to your processing methods.
Concurrency.
Paralellism would would only mean a factor 4/8. ThreadPoolExecutor and Future maybe.
OPTIMIZING THE ALGORITHM ITSELF
The set of sets could better be a List. That tremendously improves adding a set.
And shows whether the algorithm does not erroneously create identical sets.

Is it better to use arrays or a queue when merging two sorted arrays?

I'm working on a programming practice site that asked to implement a method that merges two sorted arrays. This is my solution:
public static int[] merge(int[] arrLeft, int[] arrRight){
int[] merged = new int[arrRight.length + arrLeft.length];
Queue<Integer> leftQueue = new LinkedList<>();
Queue<Integer> rightQueue = new LinkedList<>();
for(int i = 0; i < arrLeft.length ; i ++){
leftQueue.add(arrLeft[i]);
}
for(int i = 0; i < arrRight.length; i ++){
rightQueue.add(arrRight[i]);
}
int index = 0;
while (!leftQueue.isEmpty() || !rightQueue.isEmpty()){
int largerLeft = leftQueue.isEmpty() ? Integer.MAX_VALUE : leftQueue.peek();
int largerRight = rightQueue.isEmpty() ? Integer.MAX_VALUE : rightQueue.peek();
if(largerLeft > largerRight){
merged[index] = largerRight;
rightQueue.poll();
} else{
merged[index] = largerLeft;
leftQueue.poll();
}
index ++;
}
return merged;
}
But this is the official solution:
public static int[] merge(int[] arrLeft, int[] arrRight){
// Grab the lengths of the left and right arrays
int lenLeft = arrLeft.length;
int lenRight = arrRight.length;
// Create a new output array with the size = sum of the lengths of left and right
// arrays
int[] arrMerged = new int[lenLeft+lenRight];
// Maintain 3 indices, one for the left array, one for the right and one for
// the merged array
int indLeft = 0, indRight = 0, indMerged = 0;
// While neither array is empty, run a while loop to merge
// the smaller of the two elements, starting at the leftmost position of
// both arrays
while(indLeft < lenLeft && indRight < lenRight){
if(arrLeft[indLeft] < arrRight[indRight])
arrMerged[indMerged++] = arrLeft[indLeft++];
else
arrMerged[indMerged++] = arrRight[indRight++];
}
// Another while loop for when the left array still has elements left
while(indLeft < lenLeft){
arrMerged[indMerged++] = arrLeft[indLeft++];
}
// Another while loop for when the right array still has elements left
while(indRight < lenRight){
arrMerged[indMerged++] = arrRight[indRight++];
}
return arrMerged;
}
Apparently, all the other solutions by users on the site did not make use of a queue as well. I'm wondering if using a Queue is less efficient? Could I be penalized for using a queue in an interview for example?
As the question already states that the left and right input arrays are sorted, this gives you a hint that you should be able to solve the problem without requiring a data structure other than an array for the output.
In a real interview, it is likely that the interviewer will ask you to talk through your thought process while you are coding the solution. They may state that they want the solution implemented with certain constraints. It is very important to make sure that the problem is well defined before you start your coding. Ask as many questions as you can think of to constrain the problem as much as possible before starting.
When you are done implementing your solution, you could mention the time and space complexity of your implementation and suggest an alternative, more efficient solution.
For example, when describing your implementation you could talk about the following:
There is overhead when creating the queues
The big O notation / time and space complexity of your solution
You are unnecessarily iterating over every element of the left and right input array to create the queues before you do any merging
etc...
These types of interview questions are common when applying for positions at companies like Google, Microsoft, Amazon, and some tech startups. To prepare for such questions, I recommend you work through problems in books such as Cracking the Coding Interview. The book covers how to approach such problems, and the interview process for these kinds of companies.
Sorry to say but your solution with queues is horrible.
You are copying all elements to auxiliary dynamic data structures (which can be highly costly because of memory allocations), then back to the destination array.
A big "disadvantage" of merging is that it requires twice the storage space as it cannot be done in-place (or at least no the straightforward way). But you are spoiling things to a much larger extent by adding extra copies and overhead, unnecessarily.
The true solution is to copy directly from source to destination, leading to simpler and much more efficient code.
Also note that using a sentinel value (Integer.MAX_VALUE) when one of the queues is exhausted is a false good idea because it adds extra comparisons when you know the outcome in advance. It is much better to split in three loops as in the reference code.
Lastly, your solution can fail when the data happens to contain Integer.MAX_VALUE.

Remove duplicates from array by adding non-duplicates to new array

I need to remove duplicate elements from an array by adding elements that are not repeated in the original array to a new array and output the contents of that.
The problem I am having is that when the new array with no duplicates is printed there are zeros being outputted also.
Thus: does Java fill the array with zeros?
public static boolean hasDuplicates(int arrayNum[])
{
boolean dupFound = false;
int ctr1 =0;
while (ctr1<arrayNum.length && !dupFound)
{
int ctr2 = ctr1+1; // be 1 ahead each time ctr1 increments
while(ctr2<arrayNum.length)
{
if(arrayNum[ctr1] == arrayNum[ctr2])
dupFound = true;
ctr2++;
}
ctr1++;
}
return dupFound;
}
public static int[] removeDuplicates(int[] arrayNum)
{
if(hasDuplicates(arrayNum) == false)
return arrayNum;
else
{
int outArray[] = new int[arrayNum.length];
int ctr1=0;
int ctr2 = ctr1+1;
int index = 0;
boolean dupFound = false;
while(ctr1<arrayNum.length)
{
dupFound = false;
ctr2 = ctr1+1;
while(ctr2<arrayNum.length && !dupFound)
{
if(arrayNum[ctr1] == arrayNum[ctr2])
dupFound = true;
ctr2++;
}
if(dupFound == false)
{
outArray[index] = arrayNum[ctr1];
index++;
}
ctr1++;
}
return outArray;
}
}
public static void testRemoveDuplicates()
{
Scanner input = new Scanner(System.in);
System.out.println("Enter size of input array");
int array[] = new int[input.nextInt()];
System.out.println("Enter number of ints required");
for(int i=0; i<array.length; i++)
{
array[i] = input.nextInt();
}
int outArray[] = new int[array.length];
outArray = removeDuplicates(array);
for(int i=0; i<outArray.length; i++)
{
System.out.println(outArray[i]);
}
}
Here:
int outArray[] = new int[array.length];
That code assumes that you have exactly array.length array elements in your output array. And that is of course a too high number! The point is: when you create a new array of that size, the whole array is initially populated with 0 values. And your code will only "overwrite" a few slots of that output array; and all other slots stay at their initial 0 default value.
The point is: you first have to compute how many duplicates you have in your input array; and then you create a new array with exactly that number.
Alternatively, you could be using List<Integer> instead of int[]; as Java collections have the ability to grow dynamically. (or, you can keep increasing that array for collecting duplicates "manually"; that can be done, too - just a bit of complicated code to get there).
And the direct immediate answer is: yes, exactly - Java arrays are "pre-filled"; see here.
You can fix all of your problems (and probably make the code substantially faster in the process since it'll no longer have quadratic complexity) by using standard Java API calls to store the unique elements in a Set, and then turn the values in that set back into an array.
The main caveat is that you'd need to use Integer rather than int:
Set<Integer> s = new LinkedHashSet<Integer>(Arrays.asList(inputArray));
Integer[] outputArray = s.toArray(new Integer[0]);
The LinkedHashSet preserves insertion order, so you'll get the elements back in the same order as they originally appeared albeit without the duplicates.
May be you are wasting too much memory here by considering the worst case scenario where all input given are different while declaring the output array size. More Optimized Approach is that you can have an List<Integer> or ArrayList<Integer> which can store the unique values and then at last , If you want unique values in Array than declare the ArraySize same as the ArrayList<Integer> or List<Integer> size and just in one linear loop , You can copy all the data.
Does Java fill the array with zeros?
Yes , Whenever you declare the integer array , It will be having all its elements as 0. If you want to reset the value of Array to a particular value , You can use this method Arrays.fill(int array[] , int default_value). This can be done in O(list_size) complexity which is linear.
For your purpose more better approach would be use of HashSet<Integer> which holds only unique elements and which is Dynamic in nature so no need to waste extra space as well as it can make your work very easy.
So first you need to all elements in the HashSet<Integer> and then by using Iterator you can easily iterate through it but the insertion order can be disturbed here. So as replied by #Alnitak You can use LinkedHashSet<Integer> to have insertion order same.
A sample code using HashSet :
HashSet<Integer> set=new HashSet<Integer>();
int total_inputs=sc.nextInt();
for(int i=0;i<total_inputs;i++)
set.add(sc.nextInt());
Iterator itr=set.iterator();
while(itr.hasNext())
System.out.println((int)itr.next());
Note : Here input order will not be preserved.
Does Java fill the array with zeros?
Yes, java will initialize every element of your int array to 0. Therefore using arr.length will not work for you as it doesn't return the logical length of your array. You need to track the number of elements of your array yourself. The following line in your code has no meaning
int outArray[] = new int[array.length];
because outArray starts pointing to a different array as returned by your method removeDuplicates.
I need to remove duplicate elements from an array by adding elements
that are not repeated in the original array to a new array
The easiest thing you can do is the following way:
In your method removeDuplicates,
Find the highest number from the given input array, increment it by 1 and assign it to a variable.
int max = Arrays.stream(arrayNum).max().getAsInt() + 1;
Modify your if block from
if(arrayNum[ctr1] == arrayNum[ctr2])
dupFound = true;
to
if(arrayNum[ctr1] == arrayNum[ctr2]) {
dupFound = true;
arrayNum[ctrl] = max;
max++;
}

Unable to use Set to remove duplicate pair numbers

Let's say I want to generate 20 random numbers on a 8 by 6 grid.(8 columns, 6 rows) . Based on the answer from here:Creating random numbers with no duplicates, I wrote my code like this:
Random randomNumGenerator = new Random();
Set<Integer[][]> generated = new LinkedHashSet<Integer[][]>();
while (generated.size() < 20) {
int randomRows = randomNumGenerator.nextInt(6);
int randomColumns = randomNumGenerator.nextInt(8);
generated.add(new Integer[][]{{randomRows,randomColumns}});
}
In reality what happens is the Set see Integer[][]{{5,5}}; and Integer[][]{{5,5}};as NOT duplicate.Why? Even tho my purpose is to get 20 non-duplicate pair of numbers, this does not work. How do I fix this?
The Set checks for duplicates using the equals method (and also the hashCode method) of its inner type, but the Integer[][]'s equals method compares the memory addresses and not the contents.
Why do you use a Set of Integer[][] if you just want to store pairs?
Unfortunately, in Java there is no Pair class, but if you do not want to create your own, you can use the Map.Entry for that.
Random randomNumGenerator = new Random();
Set<Map.Entry<Integer, Integer>> generated = new LinkedHashSet<>();
while (generated.size() < 20) {
int randomRows = randomNumGenerator.nextInt(6);
int randomColumns = randomNumGenerator.nextInt(8);
generated.add(new AbstractMap.SimpleEntry<>(randomRows,randomColumns));
}
System.out.println(generated);
Array equals is == in Java, so an array is only equal to itself. Normaly you use Arrays.equals(array1, array2) to compare them by content, but in this case, arrays are simply the wrong choice. You can either create a bean, as rafalopez79 suggested of use an array of Collections (List in your case), as a List will compare the content on equals, see the documentation. Choice is pretty much yours, a bean would probably be a bit cleaner.
How about this code. I ran it through the debugger, it works nicely and yes, the contains() method checks the value of the Integer, not the reference. You can change the range of the random number as needed, I used 5 to facilitate testing. Yes I know it's not very robust, as written this will be an endless loop (because of the limited range of 5) but it's a simple example to make the point.
UPDATE: Actually this has a bug in that it won't check for uniqueness across all the rows, but that's easily fixed as well. I just re-read the original question and looking at the original code I'm not sure I know what you want exactly. If you just want a grid with 48 unique Intergers arranged 8 by 6 this will do it, but there are several ways to do this.
final int rows = 6;
final int cols = 8;
Random randomGenerator = new Random();
ArrayList[] grid = new ArrayList[rows];
for(int i=0; i<rows; i++)
{
grid[i] = new ArrayList<Integer>();
for(int j=0; j<cols; j++)
{
for(;;)
{
Integer newInt = new Integer(randomGenerator.nextInt(5));
if(!grid[i].contains(newInt))
{
grid[i].add(newInt);
break;
}
}
}
}

List.add() Class Expected

I'm taking a Java class in College. My instructor is actually a teacher for languages derived from C, so she can't figure out what's going on with this piece of code. I read on this page http://docs.oracle.com/javase/6/docs/api/java/util/List.html that I could use the syntax "list[].add(int index, element)" to add specific objects or calculations into specific indexes, which reduced the amount of coding needed. The program I'm looking to create is a random stat generator for D&D, for practice. The method giving the error is below:
//StatGenrator is used with ActionListener
private String StatGenerator ()
{
int finalStat;
String returnStat;
//Creates an empty list.
int[] nums={};
//Adds a random number from 1-6 to each list element.
for (int i; i > 4; i++)
nums[].add(i, dice.random(6)+1); //Marks 'add' with "error: class expected"
//Sorts the list by decending order, then drops the
//lowest number by adding the three highest numbers
//in the list.
Arrays.sort(nums);
finalStat = nums[1] + nums[2] + nums[3];
//Converts the integer into a string to set into a
//texbox.
returnStat = finalStat.toString();
return returnStat;
}
My end goal is to use some kind of sorted list or method of removing the lowest value in a set. The point of this method is to generate 4 random numbers from 1-6, then drop the lowest and add the three highest together. The final number is going to be the text of a textbox, so it is converted to a string and returned. The remainder of the code works correctly, I am only having trouble with this method.
If anyone has any ideas, I'm all ears. I've researched a bit and found something about using ArrayList to make a new List object, but I'm not sure on the syntax for it. As a final note, I tried looking for this syntax in another question, but I couldn't find it anywhere on stackoverflow. Apologies if I missed something, somewhere.
'int nums[]' is not a List, it's an array.
List<Integer> intList = new ArrayList<>();
creates a new ArrayList for example.
You can access Elements in the list directly with the following Syntax :
intList.get(0); // Get the first Element
You can sort Lists with the Collections class :
Collections.sort(intList);
Here are some informations about Collections in Java : http://docs.oracle.com/javase/tutorial/collections/
Arrays are fixed size, so you need to allocate space for all the slots at the start. Then to put numbers into the array assign to nums[i]. No add() method needed.
int[] nums = new int[4];
for (int i = 0; i < 4; i++)
nums[i] = dice.random(6) + 1;
Arrays.sort(nums);
finalStat = nums[1] + nums[2] + nums[3];
Alternatively, if you really want a dynamically-sized array, use an ArrayList. An ArrayList can grow and shrink.
List<Integer> nums = new ArrayList<Integer>();
for (int i = 0; i < 4; i++)
nums.add(dice.random(6) + 1);
Collections.sort(nums);
finalStat = nums.get(1) + nums.get(2) + nums.get(3);
Notice how different the syntax is due to ArrayList being a class rather than a built-in type.
nums[].add(i, dice.random(6)+1); //Marks 'add' with "error: class
expected"
You are trying to use add on an array. List is a dynamic array, but that doesn't mean that array == List. you should use List instead.
List<Integer> nums=new ArrayList<Integer>();
//Adds a random number from 1-6 to each list element.
for (int i; i > 4; i++)
nums.add(i, dice.random(6)+1);
You're mixing arrays and lists.
Have a look at the tutorial:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
http://docs.oracle.com/javase/tutorial/collections/index.html

Categories