Counting Int Occurrences in an Array - java

I am trying to count the occurrences of integers in an array. I was able to get it to work by piecing together some code I found online but I don't really understand why its working. What I have is:
int[] hand = {2, 4, 3, 2, 4};
int[] numOccurence = new int[hand.length];
for (int i = 0; i < hand.length; i++)
numOccurence[hand[i]]++;
for (int i = 1; i < numOccurence.length; i++)
if (numOccurence[i] > 0)
System.out.println("The number " + i + " occurs " + numOccurence[i] + " times.");
The output is:
The number 2 occurs 2 times.
The number 3 occurs 1 times.
The number 4 occurs 2 times.
How is this code counting the number of occurrences properly? I don't see how its accomplishing this. Thank you in advance!

This is only working because you've a good luck. Try making the second element in the hand array as 5 and see what happens. Its because the number present at the current index of hand is taken as the index of array numOccurence. In case of a number greater than or equal to the length of the numOccurence, you'll get the ArrayIndexOutOfBoundsException.
Thereforce, you can better use a Map for this where the key would be the number and the value could be its count.
Something like this:-
Map<Integer, Integer> numOccurence = new HashMap<Integer, Integer>();
for (int i = 0; i < hand.length; i++) {
int cnt = 1;
if (numOccurence.containsKey(hand[i])) {
cnt = numOccurence.get(hand[i]);
cnt++;
}
numOccurence.put(hand[i], cnt);
}

This code does not really work. At least it does for the author's use case but probably not for yours.
Try with {2, 4, 99, 2, 4}; as hand and it will fail.
The author takes the number found in hand as the index of array numOccurence.
numOccurence has the following structure : {nb occ of 0; nb occs of 1;...; nb occs of 4}. Here 99 will be out of bounds.

When you create an array
int[] numOccurence = new int[hand.length];
it is populated by their default values. For primitive int this value is 0.
This will of course only work if hand contains numbers less than or equal to max index (length -1) of the array otherwise it's ArrayIndexOutOfBound for you mister!

Actually it's the same method for creating histogram for picture ;)
You create a table where you will gather the occurrence.
numOccurence[0] will stock the number of 0
numOccurence[1] will stock the number of 1
etc.
That's what is done by this
for (int i = 0; i < hand.length; i++)
numOccurence[hand[i]]++;
it adds 1 to the value in the case corresponding to the number hand[i]
so if you look at this step by step
first he will take hand[0] = 2
so he will put
numOccurence[2] = numOccurence[2] + 1 ;
which is same (but faster to write) as
numOccurence[2]++;

This kind of performing a count is called counting sort.
The advantage of counting sort is it's speed. The disadvantage is the memory requirements when sorting big numbers.
There is a bug in the code:
int[] numOccurence = new int[hand.length];
numOccurence needs to be as long as the highest number in the list (not the number of numbers in the list). Try changing one of the numbers to 15 and you will get an exception.

The code iterates through the given array hand. it takes each value encountered as an index into the array numOccurrence. for each number n in hand, this will happen exactly as often as n occurs in hand, and each time this happens, the nth element of numOccurrence will be incremented.
thus numOccurrence is effectively an array of counters (assuming that the array elements are initialized with 0).
drawbacks of this approach:
the number of counters allocated depends on the magnitude of numbers in your handarray.
if the numbers in your hand array are distributed sparsely, most of the allocated space is never used.
alternative
you could improve the code by sorting hands first. in the sorted array the indexes of all occurrences of a given number are contiguous, so you scan the sorted array once needing a single counter only to compile the frequencies.

First of all the code is wrong. You should set the size of numOccurence array to the max number value from hand array + 1. For example:
int[] hand = {2, 100};
int[] numOccurence[] = new int[101];
(you should obviously find max number programatically)
Now let's take a look at the algorithm.
It takes each number from hand array, treats it as a numOccurence index value and increments number at that index by 1 in hand array. Note that all elements of numOccurence array are 0 by default at the beginning.
int[] hand = {2, 4, 3, 2, 4};
int[] numOccurence = new int[5];
Steps:
i = 0 (nothing happens, because there is no 0 in hand array)
i = 1 (same situation as for 0)
i = 2 (there are two 2 numbers in hand array, so we do operation numOccurence[2] += 1 twice, which in result gives 0 + 1 + 1 = 2. So we got numOccurence[2] = 2)
it continues for all numbers from 0 to max number from hand array (here: 100).

Related

How to merge arrays in alternating pattern without duplicates

I'm currently learning in school but am unable to complete this part of the assignment.
An explanation with the use of for loops would be greatly appreciated.
The numbers should be added to the merged array in an alternating pattern: first from list 1, then from list 2, then list 1 again, etc. If a number in one of the arrays already appears in the merged array, then it should be ignored, and the program should alternate to the other list again. For example, if the first list begins 1 2 3 10, and the second begins 3 4 5 8, then the merged list would begin 1 3 2 4 5 10 8.
Because the number of elements in the merged array is unknown, its size should be set to the maximum possible number of elements it should contain, and after all elements which should form the merged array appear, any remaining unfilled spaces in the array should be 0. The first 0 encountered in the array should signal the end of the “actual” elements of the array, and therefore the 0s at the end of the array should not be printed by your program.
I propose to use a HashSet to remember which number you have already inserted into the array. For each number, you first check if the hash set already contains the number; if not, you add it to both the array and the set. For large inputs, this is much faster than checking the result array for each number. O(n*log(n)) or so (depending on how well the HashSet works for your input) instead of O(n^2).
#bubble
An example using a Set is very simple - however your teacher is asking for
an alternate list:
Integer[] one = new Integer[] {10,2,3,1};
Integer[] two = new Integer[] {3,8,5,4};
List<Integer> li_one = Arrays.asList(one); // First convert the arrays to a list
List<Integer> li_two = Arrays.asList(two);
Set<Integer> set = new HashSet<>();
set.addAll(li_one);
set.addAll(li_two);
System.out.println("The unique list is: " + set);
A HashSet was my first idea too, but the order of storing values depends
one hash values. The ... teacher likes to have alternating values which
I dont like to comment - because it is a really strange request.
Following code prints: merged list is: [1, 3, 2, 4, 5, 10, 8]
int[] one = new int[] {1,2,3,10};
int[] two = new int[] {3,4,5,8};
int one_len = one.length;
int two_len = two.length;
List<Integer> merged = new ArrayList<>();
int oneval,twoval;
for (int i = 0;i < one_len;i++)
{
oneval = one[i];
if (!merged.contains(oneval)) merged.add(oneval);
if (i < two_len)
{
twoval = two[i];
if (!merged.contains(twoval)) merged.add(twoval);
}
}
if (two_len > one_len)
{
for (int i = one_len; i < two_len;i++)
{
twoval = two[i];
if (!merged.contains(twoval)) merged.add(twoval);
}
}
System .out.println("merged list is: " + merged);

Java Recursion to find MAX sum in array

I am trying to figure out a solution to calculate the highest sum of numbers in an array. However, my limitation is that I cannot use adjacent values in the array.
If I am given the array int [] blocks = new int[] {15, 3, 6, 17, 2, 1, 20}; the highest sum calculated is 52 (15+17+20).
My goal is to go from a recursive solution to a solution that uses dynamic programming, however, I am having trouble with the recursive solution.
The base cases that I have initialized:
if(array.length == 0)
return 0;
if(array.length == 1)
return array[0];
After creating the base cases, I am unsure of how to continue the recursive process.
I initially tried to say that if the array was of certain length, then I can calculate the max(Math.max) of the calculations:
e.g. if array.length = 3
return Math.max(array[0], array[1], array[2], array[0]+ array[2])
The problem I then run into is that I could be given an array of length 100.
How can I use recursion in this problem?
I think recursive solution to your problem is (in pseudocode):
maxsum(A,0) = 0
maxsum(A,1) = A[0]
maxsum(A,k) = max(maxsum(A,k-2)+A[k-1], maxsum(A,k-1)), for k >= 2
Where maxsum(A,k) means the maximal sum for a subarray of array A starting from 0 and having length k. I'm sure you'll easily translate that into Java, it translates almost literally.

Array Duplicate Efficiency Riddle

Recently in AP Computer Science A, our class recently learned about arrays. Our teacher posed to us a riddle.
Say you have 20 numbers, 10 through 100 inclusive, right? (these numbers are gathered from another file using Scanners)
As each number is read, we must print the number if and only if it is not a duplicate of a number already read. Now, here's the catch. We must use the smallest array possible to solve the problem.
That's the real problem I'm having. All of my solutions require a pretty big array that has 20 slots in it.
I am required to use an array. What would be the smallest array that we could use to solve the problem efficiently?
If anyone could explain the method with pseudocode (or in words) that would be awesome.
In the worst case we have to use an array of length 19.
Why 19? Each unique number has to be remembered in order to sort out duplicates from the following numbers. Since you know that there are 20 numbers incoming, but not more, you don't have to store the last number. Either the 20th number already appeared (then don't do anything), or the 20th number is unique (then print it and exit – no need to save it).
By the way: I wouldn't call an array of length 20 big :)
If your numbers are integers: You have a range from 10 to 100. So you need 91 Bits to store which values have already been read. A Java Long has 64 Bits. So you will need an array of two Longs. Let every Bit (except for the superfluous ones) stand for a number from 10 to 100. Initialize both longs with 0. When a number is read, check if the corresponding bit mapped to the read value is set to 1. If yes, the read number is a duplicate, if no set the bit to 1.
This is the idea behind the BitSet class.
Agree with Socowi. If number of numbers is known and it is equal to N , it is always possible to use N-1 array to store duplicates. Once the last element from the input is received and it is already known that this is the last element, it is not really needed to store this last value in the duplicates array.
Another idea. If your numbers are small and really located in [10:100] diapason, you can use 1 Long number for storing at least 2 small Integers and extract them from Long number using binary AND to extract small integers values back. In this case it is possible to use N/2 array. But it will make searching in this array more complicated and does not save much memory, only number of items in the array will be decreased.
You technically don't need an array, since the input size is fixed, you can just declare 20 variables. But let's say it wasn't fixed.
As other answer says, worst case is indeed 19 slots in the array. But, assuming we are talking about integers here, there is a better case scenario where some numbers form a contiguous interval. In that case, you only have to remember the highest and lowest number, since anything in between is also a duplicate. You can use an array of intervals.
With the range of 10 to 100, the numbers can be spaced apart and you still need an array of 19 intervals, in the worst case. But let's say, that the best case occurs, and all numbers form a contiguous interval, then you only need 1 array slot.
The problem you'd still have to solve is to create an abstraction over an array, that expands itself by 1 when an element is added, so it will use the minimal size necessary. (Similar to ArrayList, but it doubles in size when capacity is reached).
Since an array cannot change size at run time You need a companion variable to count the numbers that are not duplicates and fill the array partially with only those numbers.
Here is a simple code that use companion variable currentsize and fill the array partially.
Alternative you can use arrayList which change size during run time
final int LENGTH = 20;
double[] numbers = new double[LENGTH];
int currentSize = 0;
Scanner in = new Scanner(System.in);
while (in.hasNextDouble()){
if (currentSize < numbers.length){
numbers[currentSize] = in.nextDouble();
currentSize++;
}
}
Edit
Now the currentSize contains those actual numbers that are not duplicates and you did not fill all 20 elements in case you had some duplicates. Of course you need some code to determine whither a numbers is duplicate or not.
My last answer misunderstood what you were needing, but I turned this thing up that does it an int array of 5 elements using bit shifting. Since we know the max number is 100 we can store (Quite messily) four numbers into each index.
Random rand = new Random();
int[] numbers = new int[5];
int curNum;
for (int i = 0; i < 20; i++) {
curNum = rand.nextInt(100);
System.out.println(curNum);
boolean print = true;
for (int x = 0; x < i; x++) {
byte numberToCheck = ((byte) (numbers[(x - (x % 4)) / 4] >>> ((x%4) * 8)));
if (numberToCheck == curNum) {
print = false;
}
}
if (print) {
System.out.println("No Match: " + curNum);
}
int index = ((i - (i % 4)) / 4);
numbers[index] = numbers[index] | (curNum << (((i % 4)) * 8));
}
I use rand to get my ints but you could easily change this to a scanner.

Given an array of +ve integers, Find the number which occurs odd number of times in O(n) time & constant space.

Given an array of positive integers. All numbers occur even number of times except one number which occurs odd number of times. Find the number in O(n) time & constant space.
int getOddOccurrence ( int ar[]){
int i;
int res = 0;
for (i = 0; i < ar.size; i++)
res = res ^ ar[i];
return res;
}
/* Diver function to test above function */
PSVM() {
int ar[] = {2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2};
SOP(getOddOccurrence(ar));
}
Approach 1: By X-OR ing all the elements in an array
I am trying to x-or all the elements. Is that the
correct approach? Above is the code using X-OR
Approach 2: By using HashMap
If I use hashmap , the space complexity would be O(n). Which is not good.
Which approach should I use?
This problem assumes there is only one number which occurs odd number of
times in the array. If you have more such numbers - say K of them: a1, a2, ... aK,
then at the end of the loop, in res you will get this value.
res == a1 ^ a2 ^ ... ^ aK
From that value you cannot infer/extract all K unknown numbers a1, a2, ... aK.
Buf ... you see, if K=1 (i.e. if you have exactly one number occurring
odd number of times), at the end you will get in res just that number.
Use the first approach as long as you understand why it works.
Also, in the second approach the space is not O(n) but O(s),
where s is the count of distinct values in your array. And as you
have only 1 number occurring odd number of times we can say for sure
that 2*s + 1 <= n i.e. s <= (n-1)/2. So the space complexity
is O((n-1)/2) in the second approach. You achieve it when your array
looks like this: s numbers occurring twice, and 1 number occurring once.

Java how to add a Random Generator that excludes a certain number?

Suppose I wanted to generate random numbers taken from ArrayList:(1,2,3,4,5,6,7,8,9,10)
A Random Generator produces 5.
List gets updated- AL:(1,2,3,4,6,7,8,9,10)
Next Random Number cannot be 5.
I am writing a program that generates random numbers from a arraylist and once it generates the random number the list removes that number and the next random generated digit cannot be that number.
ArrayList<Integer> numsLeft = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
Random randomGenerator = new Random();
int number = 0;
String cont;
do
{
number = randomGenerator.nextInt(numsLeft.size());
numsLeft.remove(number);
System.out.println (number + " continue (y/n)");
cont = (stdin.readLine());
}
while (cont.equalsIgnoreCase("y"));
But the only thing I can do here is lower the size...
http://docs.oracle.com/javase/7/docs/api/java/util/Random.html
The easier approach is to simply shuffle your list then use the numbers in the shuffled order:
List<Integer> nums = new ArrayList<Integer>();
for (int i = 1; i < 11; i++)
nums.add(i);
Collections.shuffle(nums);
Now they are in random order, just use them one by one:
for (Integer i : nums) {
// use i
}
You could make an array of the available numbers. Then, the random number generator gives you the position in that array for the number that you want.
Probably a linked list or something would be more efficient, but the concept is the same.
So, with your example, you'd pull 5 the first time. The second time, you'd have this in your list:
1, 2, 3, 4, 6, 7, 8, 9
If your random number was 5 again, the fifth position is 6. Pop the six out, shift 7, 8, 9 over one, and decrement your random number generator to be 1-8 instead of 1-9. continue on.
of course, looking at your code, it looks like that is what you are trying to do already.
What seems to be the issue with your code? What results are you getting?
number = randomGenerator.nextInt(numsLeft.size());
numsLeft.remove(number);
You are now printing the random index that you are generating, not the number that was removed from the list. Is that what you wanted? I think you really meant this:
int index = randomGenerator.nextInt(numsLeft.size());
number = numsLeft.remove(index);
You could also do this using by randomly shuffling the list and then just going through it:
List<Integer> numsLeft = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
// Shuffle the list randomly
Collections.shuffle(numsLeft);
do {
// Remove the first number each time
int number = numsLeft.remove(0);
System.out.println (number + " continue (y/n)");
cont = (stdin.readLine());
} while (cont.equalsIgnoreCase("y"));
Why don't you create a hash map to take care of this. So your hash map can contain something like
Map[(1,1), (2,2), (3,3), ...] or Map[(1,true), (2,true), (3,true), ...]
So if you generate a number, then you can do something like:
String value = map.get(key); or boolean present = map.get(key);
if(value != null) or if(value == present)
map.remove(key), or you can even update the data and instead of removing the key you can update it and add the word removed or a boolean as previously suggested. But this way you can keep track of all the entries and removals in your map for each of the key values which would be your list of numbers.
remove can be pretty expensive operation when list is long. Shuffle is too - especially if you only need a few numbers. Here is another algorithm (it is famous but I can't find the source right now).
put your N (ordered) numbers in a list
Choose a random number m between 0 and N-1
Pick the element at location m. This is your unique random number
SWAP element m with the LAST element in the array
Decrement N by 1
Go to step 2
You "set aside" the numbers you have used in step 4 - but
Unlike shuffle, your initialization is fast
Unlike remove, your remove operation only takes moving one element (instead of, on average, N/2)
Unlike the "pick one and reject if you saw it before", your efficiency of picking a "new" number doesn't decrease as the number of elements picked increases.

Categories