Generating an array of non-repeating integers - java

I'm trying to generate an array of 5 non-repeating integers in Java, but there are still repeats when I run it. Here's my code so far:
public int[] generateCode(){
code[0] = (int)Math.round(Math.random()*8+1); // initialize first number so it won't be compared against
for(int i=1; i<code.length; i++){
code[i] = (int)Math.round(Math.random()*8)+1;
for(int j=0; j<i; j++){
while(code[i]==code[j]){
code[i] = (int)Math.round(Math.random()*8)+1;
}
} // end inner for loop
} // end outer for loop
return code;
} // end generateCode method
Any help is very much appreciated!

So, your for-loop is checking for repeated characters, BUT each time you generate a new value (in the while-loop) you're not checking to see if the value exits before j.
There are a number of possible ways you might address this issue, I prefer ones which uses Collections.shuffle, but assuming that you can't use features like Arrays, Collections, List, Set or possibly even streams, we need to work with what we have, arrays.
Since you have a small range of acceptable values which need to fit into an even smaller range, a simple solution might be to generate a "master" list of allowed values and randomly select a value from the master list, tracking which values you've already picked.
Sounds more complicated then it actually is, for example...
public int[] generateCode() {
int[] masterValues = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] codes = new int[5];
Random rnd = new Random();
int index = 0;
while (index < codes.length) {
int lookupIndex = 0;
do {
lookupIndex = rnd.nextInt(masterValues.length);
} while (masterValues[lookupIndex] == 0);
codes[index] = masterValues[lookupIndex];
masterValues[lookupIndex] = 0;
index++;
}
return codes;
}
This creates a "master" list of values. It then randomly calculates a "lookup" index, checks to see if the value in the master list is 0 or not, if not, it assigns it to the next index in the codes array and sets the value in the master list to 0, otherwise it generates a new random index and tries again. This all repeats till it fills the codes array
So doing something like...
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
could print (because it's "random")...
[8, 1, 4, 7, 5]
[9, 6, 2, 1, 8]
[6, 5, 9, 4, 7]
[2, 5, 3, 1, 4]

There are much easier ways to do this. Using a Set<Integer> would be one. Here is another.
List<Integer> list = new ArrayList<>(List.of(1,2,3,4,5,6,7,8));
Collections.shuffle(list);
System.out.println(list.subList(0,5));
prints something like
[4, 5, 8, 2, 1]
As was pointed out to me, you may not be allowed to use or know about collections. But I would recommend you at least make a helper method to check for duplicates to reduce the clutter. Something like the following:
public boolean contains(int[] arr, int n) {
for (int v : arr) {
if (v == n) {
return true;
}
}
return false;
}
Then you can keep checking the current value to be false before you add it. Once it works it also lets you focus on other aspects of your code.

Related

Failing Two Test Cases, Missing Integer Codility Problem

The Question:
Write a function, that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
For example, given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [−1, −3], the function should return 1.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [−1,000,000..1,000,000].
What I'm not understanding is how I'm failing these two cases, while also having 100% correctness
Also I'm not sure what cases I'm not covering, I managed for the case of 1 not existing in the first if statement, if there is a missing element in my for each loop, and finally, in the case of no missing element, to return the largest int + 1
Any help in clearing the confusion (and improvements for my time complexity) would be greatly appreciated
import java.lang.*;
import java.util.*;
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
//int counter = 0;
Set<Integer> set = new HashSet<Integer>();
Arrays.sort(A);
for(int n : A){
if(n > 0){
// counter++;
set.add(n);
}
}
//returns if set does not contain 1
if(!set.contains(1)){
return 1;
}
//returns missing int if it does not exist in set
for(int n: set){
if(!set.contains(n+1)){
return n+1;
}
}
//if no missing ints, returns end of array + 1
return A[A.length-1];
}
}
Answer Results:
I think you over-killed. first, using a hashset can lead to O(N) algorithm, which you have to avoid sort (O(NlogN)). But due to large memory footprint, I'd rather go with a sort and it is practically faster. Second, if you choose a sort of A, then a simple for-loop with detect any gap in the positive part of the array, which is now your result. You should avoid Hashset and the many loops in your code
I would use a BitSet.
Advantage: Fast scan for missing value. Performance: O(n)
public static int solution(int... values) {
BitSet bitSet = new BitSet();
for (int v : values)
if (v > 0)
bitSet.set(v);
return bitSet.nextClearBit(1);
}
Test
System.out.println(solution(1, 3, 6, 4, 1, 2));
System.out.println(solution(1, 2, 3));
System.out.println(solution(-1, -3));
Output
5
4
1

I am getting a default value of 0 when I attempt to insert value in array after the I sorted

I have an integer array of size 4. I am adding elements to it via the add method. This is as an unsorted array. I am sorting it via the sort method shown in the code below. The sort method places the smallest number in the position a[0]. When I try to add elements after I call the sort method I always get a return value of 0. Is there a way around this?
import java.util.Arrays;
public class Scrap {
private static int[] array = new int[4];
private static int i = 0;
public static void main(String[] args) {
Scrap pq = new Scrap();
pq.add(4);
pq.insert(3);
pq.add(5);
pq.sort();// smallest to largest sort method.
// System.out.println(array[0]);
pq.insert(1);
pq.sort();
int test = pq.Minimum();
System.out.println("The smallest element of the array is " + test);
pq.sort();
}
//
public void add(int input) {
insert(input);
}
// Method to insert number into the array.
public void insert(int input) {
array[i] = input;
i++;
}
// Finding smallest number of the array.
public int Minimum() {
int a = array[0];
return a;
}
// Sorts the array from smallest to largest integer
public void sort() {
int first, temp;
for (int i = array.length - 1; i > 0; i--) {
first = 0;
for (int j = 1; j <= 1; j++) {
if (array[j] > array[first])
first = j;
}
temp = array[first];
array[first] = array[i];
array[i] = temp;
}
}
public int remove() {
return delete();
}
public int delete() {
return remove();
}
// Method to convert the array into a string for output
}
The problem in a nutshell:
You start with an array of length 4.
At this point the array contains 4 zeros, that is: [0, 0, 0, 0]
You add 4, 3, and 5. These operations update the content of the array to [4, 3, 5, 0].
You sort the array. This should change the content of the array to [0, 3, 4, 5]. In fact it changes to [0, 5, 3, 4], which means your implementation of sort is clearly broken.
You probably didn't expect the 0 value to move. You can fix this by sorting only the first 3 values. (And, of course, you should also fix your implementation of sort.)
Then when you insert 1, the program updates the value at index 3, so the content changes to [0, 5, 3, 1].
If you implement the fix I suggested above, and sort only the first size elements, then the content after the first call to sort should become [3, 4, 5, 0], and the content after the insert 1 should become [3, 4, 5, 1]. And when you sort that again, the content should become [1, 3, 4, 5] and the smallest value will be 1 as expected, instead of 0.
More concretely:
First of all, change private static int i = 0; to private int size = 0;. The name i is extremely inappropriate here, and will surely confuse you. size is appropriate. It also doesn't make sense to make it static, so I suggest to drop that keyword.
Fix the implementation of sort. There are many basic sorting algorithms that are easy to implement. In the implementation, instead of going until array.size, go until size. Do you see the difference? size is the field in Scrap, essentially it's the number of elements you added using the add or insert methods.
Some cleaning up would be good too:
Delete the add method and rename insert to add.
Delete the remove and delete methods. They are not used, and you will get a stack overflow if you try to use them as they are now (the methods call each other, forever)
Look at the content of the array after each step in the program.
After Scrap pq is created, this is the content of its array:
[0, 0, 0, 0]
Then a couple of modifications:
pq.add(4);
pq.insert(3);
pq.add(5);
The content at this point:
[4, 3, 5, 0]
So far so good.
Then you sort it:
pq.sort();
The content at this point:
[0, 5, 3, 4]
Ouch. The sort implementation doesn't work very well, does it. But let's ignore that for now. Next step:
pq.insert(1);
The content at this point:
[0, 5, 3, 1]
None of this behavior makes sense, probably this is not how you intended the program to work. Review the program, verify the content after each step. Do not proceed to the next step until the current step is working correctly.
I am assuming that you will be using a correct sort method (because, this is not correct, you can use Arrays.sort). But still with a correct sort, there is a logical problem in your code.
At the beginning, the array contains all 0s. After adding the first 3 int, when you call the sort method, the array contains the values in following order:
0,3,4,5
Note that, the value of i is not changed. At this state the value of i is 3. So when you insert 1, the new values become
0,3,4,1
So after sorting again, the values of arrays become
0,1,3,4
So obviously the minimum will retrun 0
I don't think that is the most effective way to sort an array. It is possible to do this with just 1 for loop. Try this to sort your array from smallest to largest.
int temp;
for(int i=0;i<array.length-1;i++){
if(array[i]>array[i+1]){
temp=array[i];
array[i]=array[i+1];
array[i+1]=temp;
i=-1;
}
}

algorithm to get subset of array with target sum is not giving working

The problem is given an unsorted array, give subsets of array that can produce target sum:
For eg:
target = 15
data = {3,4,5,7,1,2,9};
Expected results (note the results are sorted for simplicity. not a requirement) :
[1, 2, 3, 4, 5]
[1, 2, 3, 9]
[1, 2, 5, 7]
[1, 3, 4, 7]
[1, 5, 9]
[2, 4, 9]
[3, 5, 7]
Here is my naive approach to this problem - simple and brute force.
public static void naiveSubset(int[] arr, int target){
int sum=0;
List<Integer> result = new ArrayList<>();
for (int i=0; i< arr.length;i++){
sum =arr[i];
result.add(arr[i]);
for (int j=0;j<arr.length;i++){
if (sum==target){
System.out.println(result);
result.clear();
break;
}
else if (i!=j && sum+arr[j] <= target){
sum+=arr[j];
result.add(arr[j]);
}
}
}
}
For some reasons, I am not expecting the results. I tried browsing through the code to dig out any issues. But I could not find any. please algo experts, point me in correct direction!!
The results I get (for same input as above)
[3, 3, 3, 3, 3]
[9, 3, 3]
Your solution is wrong because it's a greedy approach. It decides if you should add a number or not based on the fact that adding it does not violate the sum, at the moment.
However, this greedy approach does not work, with a simple example of the following array: [1,9,6,5] and with sum=11.
Note that for any element you choose in the outer loop, next you will add 1 to the current set. But that will deny you the possibility to get the sum of 5+6.
Once you choose 5, you start adding number, starting with '1', and adding it. Once it is added - you will never get the correct solution.
Also note: Your double loop approach can generate at most O(n^2) different subsets, but there could be exponential number of subsets - so something must be wrong.
If you want to get all possible subsets that sum to the given sum, you can use a recursive solution.
At each step "guess" if the current element is in the set or not, and recurse for both options for the smaller problem - if the data is in the set, or if it's not.
Here is a simple java code that does it:
public static void getAllSubsets(int[] elements, int sum) {
getAllSubsets(elements, 0, sum, new Stack<Integer>());
}
private static void getAllSubsets(int[] elements, int i, int sum, Stack<Integer> currentSol) {
//stop clauses:
if (sum == 0 && i == elements.length) System.out.println(currentSol);
//if elements must be positive, you can trim search here if sum became negative
if (i == elements.length) return;
//"guess" the current element in the list:
currentSol.add(elements[i]);
getAllSubsets(elements, i+1, sum-elements[i], currentSol);
//"guess" the current element is not in the list:
currentSol.pop();
getAllSubsets(elements, i+1, sum, currentSol);
}
Note that if you are looking for all subsets, there could be exponential number of those - so an inefficient and exponential time solution is expected.
If you are looking for finding if such a set exist, or finding only one such set, this can be done much more efficiently using Dynamic Programming. This thread explains the logic of how it can be done.
Note that the problem is still NP-Hard, and the "efficient" solution is actually only pseudo-polynomial.
I think the major issue in your previous approach is that simply doing loops based upon the input array will not cover all the combinations of numbers matching the target value. For example, if your major loop is in ith, and after you iterate through the jth element in your secondary loop, your future combination based on what you have collected through ith element will never include jth one anymore. Intuitively speaking, this algorithm will collect all the visible combinations through numbers near each other, but not far away from each other.
I wrote a iterative approach to cope with this subset sum problem through C++ (sorry, not have a java environment at hand:P), the idea is basically the same as the recurrsive approach, which means you would record all the existing number combinations during each iteration in your loop. I have one vector<vector> intermediate used to record all the encountered combination whose value is smaller than target, and vector<vector> final used to record all the combinations whose sum is equal to target.
The detailed explanation is recorded inline:
/* sum the vector elements */
int sum_vec(vector<int> tmp){
int sum = 0;
for(int i = 0; i < tmp.size(); i++)
sum += tmp[i];
return sum;
}
static void naiveSubset(vector<int> arr, int target){
/* sort the array from big to small, easier for us to
* discard combinations bigger than target */
sort(arr.begin(), arr.end(), greater<int>());
int sum=0;
vector<vector<int> > intermediate;
vector<vector<int> > final;
for (int i=0; i< arr.size();i++){
int curr_intermediate_size = intermediate.size();
for(int j = 0; j < curr_intermediate_size; j++){
int tmpsum = sum_vec(intermediate[j]);
/* For each selected array element, loop through all
* the combinations at hand which are smaller than target,
* dup the combination, put it into either intermediate or
* final based on the sum */
vector<int> new_comb(intermediate[j]);
if(tmpsum + arr[i] <= target){
new_comb.push_back(arr[i]);
if(tmpsum + arr[i] == target)
final.push_back(new_comb);
else
intermediate.push_back(new_comb);
}
}
/* finally make the new selected element a separate entry
* and based on its value, to insert it into either intermediate
* or final */
if(arr[i] <= target){
vector<int> tmp;
tmp.push_back(arr[i]);
if(arr[i] == target)
final.push_back(tmp);
else
intermediate.push_back(tmp);
}
}
/* we could print the final here */
}
Just wrote it so please bear with me if there is any corner case that I did not consider well. Hope this helps:)

arraylist is always created with a constant capacity

I am trying to compute pascal's triangle given a row number. I am using recursion.
My code is below:
public static List<Integer> getRow(int rowIndex) {
if (rowIndex == 1){
List <Integer> list = new ArrayList(rowIndex+1);
list.add(1);
return list;
}
else{
List<Integer> oldList = getRow(rowIndex -1);
List <Integer> list = new ArrayList(rowIndex+1);
int temp = 0;
list.add(0,1);
list.add(list.size()-1,1);
System.out.println("rowIndex "+rowIndex);
for (int i = 1; i < list.size()-1; i ++){
temp = oldList.get(i) + oldList.get(i-1);
list.add(i,temp);
}
return list;
}
}
It always returns [1,1] regardless of what row I am trying to get. I tried inserting print statements. I noticed the size of list is always 2 regardless of what rowIndex is.
List <Integer> list = new ArrayList(rowIndex+1);
Is the line above not the correct way to create an ArrayList? Seems like my arraylist always has size = 2;
you misunderstand how ArrayLists do work and you really should read the Javadoc.
In short, the constructor's parameter defines the initial size of the ArrayList in memory, not the max size. If you instantiate a new ArrayList<Integer>(2)it only means that the jvm allocates upfront enough space for two Integers, and that when you add a third element then the jvm will grow the size of the ArrayList in order to allow you to add more elements.
Further, you can access an ArrayList position with get() only if an element has been added at this position.
Finally, keep in mind that add at a specific position shifts right all elements. Thus if you add(10,1) then add(2,4), your first add will be shifted right.
Back to your question, if you absolutely want to use an ArrayList and not an array, you have to initialize your ArrayList with the right size, then set values at the right positions.
Here is a working solution :
// the method with your algorithm which has been slightly modified
public static List<Integer> getRow(final int rowIndex) {
// notice that I call a helper method which initialises correctly the ArrayList
final List<Integer> list = init(rowIndex);
if (rowIndex == 1) {
// notice that I set the value at a given position
// I can only do it because I initialised all values to 0 first
list.set(0, 1);
} else {
final List<Integer> previousRowList = getRow(rowIndex - 1);
// again, I set values...
list.set(0, 1);
list.set(rowIndex - 1, 1);
for (int i = 1; i < (list.size() - 1); i++) {
// set again...
list.set(i, previousRowList.get(i - 1) + previousRowList.get(i));
}
}
// lets print out the row
System.err.println(list);
// then return it
return list;
}
public static List<Integer> init(final int size) {
// passing the size is overkill, but well...
final List<Integer> list = new ArrayList<Integer>(size);
// fill the ArrayList with zeros
for (int i = 0; i < size; i++) {
list.add(i, 0);
}
// then return it
return list;
}
public static void main(final String[] args) {
getRow(Integer.parseInt(args[0]));
}
If you run it you'll get a (not so nice, but working) Pascal's triangle. Here follows the result if you want 11 rows :
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
[1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
Hope it helps !
I think you're miss-interpreting the data structures.
And array list is a LIST implemented on top of an array. Setting the size of the array in the constructor is a way to give control to the developer for the initial size of the array (This is rarely necessary as the class manages the array size itself--so just leave out this argument). So the size of an array list is actually the size of the list, which is the number of elements, not the number of buckets in the underlying array which is specified in the constructor.
If you know the size of the array you want, and you want to get and add at specific locations, use a standard array, not an array list.
However, I think your code will work if you move
list.add(list.size()-1,1);
to after your for-loop (I'm actually surprised it doesn't throw an index out of bounds exception). And since you're going left to right, none of your adds need an index specified, since it'll just add it to the end of the existing list.

Java Unit Testing

I have a program and I am trying to write my Unit Test for it, I just need to know if it is correct? Here is the program:
public static int[] bucketSort(int[] entries)
{
int numberBuckets = maxVal(entries);
//Creates an array with maxVal buckets.
int[] buckets = new int[numberBuckets+1];
//Loop through input entries and add one to the count for every occurrence of that number in entries.
for (int i = 0; i < entries.length; i++)
{
buckets[entries[i]]++;
}
int key = 0;
for (int i = 0; i < buckets.length; i++)
{
for (int j = 0; j < buckets[i]; j++)
{
//Use the number of every occurrence of each number in entries to construct the sorted array.
entries[key] = i;
key++;
}
}
//Print out the sorted array.
for(int i = 0; i <= entries.length-1; i++)
{
System.out.print(entries[i] + ", ");
}
return entries;
}
Here is what I have for the Unit Test
import junit.framework.Assert;
import junit.framework.TestCase;
public void testBucketSort()
{
int[] a1 = {9, 6, 2, 2, 4, 1, 0, 10,};
int[] a2 = BucketSort.bucketSort(a);
int[] a3 = {0, 1, 2, 2, 4, 6, 9, 10,};
Assert.assertArrayEquals(a2, a3);
}
}
No this is not correct. There are two reasons:
You have used already sorted data. Though it should also be a test case, but you should use a random data set and apply sort on it. Keep another array like a3 as your expected array and then call assertArrayEquals on a2 and a3.
Your assertArrayEquals implementation is not verifying anything. Basically its just printing true or false but your test as such will always pass. You can use junit assertArrayEquals method from Assert class or right your own implementation where you should fail test if condition doesn't match.
Use JUnit, not your own testing method, unless you have a really good reason.
Also, think of how your code could break and write a test for each case. example:
all in order
reverse order
random order
all duplicate values
Make sure in all cases the result is exactly the right length and sorted appropriately.
The biggest problem that I see is that you're passing parameters to assertArrayEquals() in the wrong order: all JUnit assertions take parameters in the order expected, actual.
Other than that, you don't have nearly enough tests. For any array-based method, I would writeat least 4 tests: one with 0 elements, one with 1, one with 2, and one with 3. This will catch most edge cases (0, 1, 2), and give at least some assurance that your code will handle increasing sizes gracefully (3).

Categories