Hard java array situation - java

I am trying to compute this problem all day long and it seems i can't figure out how to do it:
List<ArrayList<Word>> words = new ArrayList<ArrayList<Word>>();
words index 0 has : defin 3,countri 1,chairman 2,year 1,
words index 1 has : defin 2,build 1,countri 1,round 3
words index 2 has : cup 3,patent 1,round 2,year 2,
What I want to do is to find which words belong to other arrays and add their numbers together and then divide that with first occurrence.
For example:
When index = 0 and word = defin --> 3/2+0
When index = 0 and word = countri --> 1/1+0
....
When index = 1 and word = defin --> 2/3+0
When index = 1 and word = round --> 3/2+0
....
When index = 2 and word = cup --> 3/0+0 but must do 3/1 so it wont "break".

I'm tempted to suggest Guava's Multiset, which is typically used to track multiple occurrences of the same objects -- like a Map<E, Integer>, but with much less hassle.
List<Multiset<String>> words;
int index;
Map<String, Double> ratios = Maps.newHashMap();
for(Multiset.Entry<String> entry : words.get(index).entrySet()) {
String word = entry.getElement();
int wordCountIn0 = words.get(0).count(word);
if (wordCountIn0 == 0) wordCountIn0 = 1;
ratios.put(word, (double) entry.getCount() / wordCountIn0);
}
I'm not 100% clear on your problem, but as best as I understand it, this should work.

Encapsulate your data inside a class that maintains all pertinent data in various data stores.
Then query via that object. Think of it as a databse - you have the core data, but you also have things like indexes and views that present that data in a given way according to your usage requirements.

I figured out how to do it, not the best way in terms of efficiency but it works. In any way it is not efficiency that am after but rather to make it 'just work'.
So what i do is that i loop over the size of the first array and check whether the word belongs to any of the arrays or not. When i find that i store its frequency value. Then i go over the arrays again except for that that i have found the word the first place. I sum up all the frequencies and in the end i dived the first frequency but the summed up from the others.

Related

Why HashMap is not good for a big dataset of integer keys?

I've a non-empty array A consisting of N integers is given. The array contains an odd number of elements, and each element of the array can be paired with another element that has the same value, except for one element that is left unpaired.
For example, in array A such that below:
A[0] = 9 , A[1] = 3 , A[2] = 9 , A[3] = 3 , A[4] = 9 , A[5] = 7 , A[6] = 9
I need to write a functon that returns the value of the unpaired element.
One of my first native solutions was to create a hashmap structure with unique keys - N integers of given array and iterate through the array adding values if the key is already exists in the hashmap. After all the key that has only 1 at it's value field is the unpaired element.
I know that the hashcode of Integer is it's int unique value...
So I soposed that there will not be a duplicate keys of different Integers..So I supposed that there will not be a duplicate keys for different Integers..But for a big sets of data this solution does not work...I think this has something to do with load factor.
But I can't get on it. I don't need an alterntive solution, becouse I have it already, I just want to understand what's wrong with hashmap when we use a big sets of integer keys..
Here is my code and thank you very much!:
Map a = new HashMap();
for(int i=0;i<A.length;i++) {
if(a.containsKey(A[i])){
a.put(A[i], a.get(A[i])+1);
}else a.put(A[i], 1);
}
for (Integer i : a.keySet()) {
if(a.get(i)==1)
return i;
}
return -1;
enter image description here
I think this has something to do with load factor.
No, the problem is not in the HashMap, it's in the way you are using it.
Your solution is not complete because it assumes all the pairs are unique. i.e. it assumes there can be at most one pair of 9 (which is not true in the example you posted, which contains 2 pairs of 9).
Having multiple identical pairs will not necessarily result in a wrong answer, but what
if, for example, there are 3 9's, two of them are paired, but the 3rd is not? Your solution won't find it, since a.get(9) would return 3, but you check if it's equal to 1.
Instead of checking
if(a.get(i)==1)
you should check if it's odd
if(a.get(i)%2==1)

Pseudo code: Random Permutation

I have a pseudo code that I have translated into java code but anytime I run the code, I get an empty arraylist as a result but it is supposed to give me a random list of integers.
Here is the pseudo code:
Algorithm 1. RandPerm(N)
Input: Number of cities N
1) Let P = list of length N, (|P|=N) where pi=i
2) Let T = an empty list
3) While |P| > 0
4) Let i = UI(1,|P|)
5) Add pi to the end of T
6) Delete the ith element (pi) from P
7) End While
Output: Random tour T
Here is the java code:
public static ArrayList<Integer> RandPerm(int n)
{
ArrayList<Integer> P = new ArrayList<>(n);
ArrayList<Integer> T = new ArrayList<>();
int i;
while(P.size() > 0)
{
i = CS2004.UI(1, P.size());// generate random numbers between 1 and the size of P
T.add(P.get(i));
P.remove(P.get(i));
}
return T;
}
I don't know what I am doing wrong.
ArrayList<Integer> p = new ArrayList<>(n);
... creates an empty list with an initial capacity of n.
All this does is tell the ArrayList what size array to initialise as backing store - most of the time you achieve nothing useful by specifying this.
So your while(p.size() > 0) runs zero times, because p.size() is zero at the start.
In the pseudocode "where pi=i" suggests to me that you want to initialise the list like this:
for(int i=0;i<n;i++) {
p.add(i)
}
(I have lowercased your variable name - in Java the convention is for variables to startWithALowerCaseLetter -- only class names StartWithUpperCase. It's also the Java convention to give variables descriptive names, so cityIdentifiers perhaps)
You may want to know that, even if you fix the problem that P is always empty, there are 2 more issues with your implementation.
One is that P.remove(P.get(i)) does not necessarily remove the ith item if the list has equal value items. It scans from the beginning and removes the first occurrence of the item. See ArrayList.remove(Object obj). You should use P.remove(i) instead for the correct results.
Then the performance is O(n^2). The reason is that ArrayList remove an item by shifting all the subsequent items one slot to the left, which is an O(n) operation. To get a much better performance, you can implement your own "remove" operation by swapping the item to the end. When you generate the next random index, generate it within the range [0, beginning index of the removed items at the end). Swapping is O(1) and the overall performance is O(n). This is called Knuth Shuffle by the way.

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.

Create all possible ways of putting n users into k groups

Given n users (u_1, u_2,..., u_n) and k groups (g_1, g_2, ..., g_k), create all possible combinations of all groups. basically, in the end, each combination is a Map<Integer,Integer>, where the first Integer is user ID, and the second Integer is group ID.For example, [(u_1,g_1), (u_2,g_1)....,(u_n, g_1)] is one possible combination.
There will be k^n combinations.
I searched and saw similar problems, but they do have some extra conditions that do not apply for my problem. In my case, there is no limit in each group, and there is no evenness or uniform distribution.
Can you suggest a quick way to do this in Java?
Thanks
My tries so far:
I tried to create a for loop for each possibility for each user, but I face the problem that I cannot define the number of for loops.
So I switched to recursion, but stuck at creating parameters for inside calls to the functions. Still working on it though.
Please, also note that this is not "n choose k". "n choose k" is when all users are identical, but here users are obviously not identical.
OK. I created a solution for this. Basically, it's a dynamic programming problem. Assume you have created a List of Maps (combinations) for j users and k locations. TO create for j+1 users and k locations, need 2 loop: for each Map, for each i=1 to k, Map.put(user_j+1, k)). Is is both recursive and iterative. Recursive because you need to pass the old maps to the new iterations. That's it.
The traditional solution to these kinds of problems is using recursion: If there are n = 0 users the only grouping possible is the empty group. Otherwise, take out the first user and generate the solution for the other n-1 users. Using the solution for the subproblem, generate the final solutions by assigning the first user to each of the k possible groups.
In code:
import java.util.*;
class Grouping {
public static void main(String[] args) {
List<?> groups = grouping(Arrays.asList(1,2,3), Arrays.asList(4,5,6,7));
System.out.println(groups.size());
System.out.println(groups);
}
static List<Map<Integer,Integer>> grouping(List<Integer> users, List<Integer> groups) {
if (users.isEmpty()) {
Map<Integer,Integer> empty = Collections.emptyMap();
return Collections.singletonList(empty);
} else {
Integer user = users.get(0);
List<Map<Integer,Integer>> subs = grouping(users.subList(1,users.size()), groups);
List<Map<Integer,Integer>> solutions = new ArrayList<>();
for (Integer group: groups) {
for (Map<Integer,Integer> sub : subs) {
Map<Integer,Integer> m = new HashMap<>(sub);
m.put(user, group);
solutions.add(m);
}
}
return solutions;
}
}
}
Ok, here is simple idea.
Lets first assume that each user_id is in {0, ... n-1}, and group_id is in {0, ... k-1}, we can map this numbers back to real ids later.
Now, what you basically want to do is to iterate thru all n-digit numbers in Base k numeral system, i.e. where each digit 0 <= base < k.
So, you start with number is 0000...00 (n-zeroes) and you end with kkkk....kk (n digits of nominal k). For each such number the position indicates user_id and digit value is this user's group_id.
So, the main workhorse you need to implement is the class Combination representing such n-digits sequence(try ArrayList or simple int[] array), with increment() operation implemented correctly (I imagine recursion is the best way to do this implementation). May be you could also have method isMaxReached() to check if all digits are of value k.
Then you would have a single loop :
Combination combination = new Combination(); // initialized with n -zeroes
while (!combination.isMaxReached()) {
combination.increment();
}
Please let me know if you would need more details on implementation.
Hope that helps.
It looks like we have the following:
n different numbers (users)
k sets (groups)
Objective is:
Find all the k-tuples with k sets S_k, such that for all i,j in 1..k the pairwise intersection of S_i and S_j is empty and the union S_1 .. S_k is the set 1..n
If this is what you want, then I would attack this recursively:
If n is 0, then the result is 1 k-tuple of empty sets.
If n is 1, then the results are k tuples, where for all elements S_j with j = 1..k it is the empty set except for the j-th element that is set {1}.
If n is m, then compute the list of tuples for m-1. Then replicate the list k times, and let the i-th set be the union of the i-th set and {n}. (Note that this is just a more general form of the previous rule for n=1).
Example:
n = 3, k = 2
n = 2, k = 2
n = 1, k = 2
n = 0, k= 2
result: [({},{})]
result: [({1},{}), ({},{1})]
result: [({1,2},{}), ({2},{1}), // j=1, union 1st with {2}
({1},{2}), ({},{1,2})] // j=2, union 2nd with {2}
result: [
({1,2,3},{}), ({2,3},{1}), ({1,3},{2}), ({3},{1,2}), // j=1, union 1st with {3}
({1,2},{3}), ({2},{1,3}), ({1},{2,3}), ({},{1,2,3}) // j=2, union 2nd with {3}
]
So u want maps like k1,n1, k1,nN .. kN,nN..
You will need 2 loops
Start by looping the groups . In each group, loop over all the users... and in the second loop , put(group,user) in a hashmap...
Code using the above algorithm.

Writing to arrays in Java

I have an array of integers and I want to save pairs of integers using the index of the array as one of the indexes and the value as the other integer.
For example, if I wanted to save the pair: 2, 4. I could do: dependencias[2] = 4 (or dependencias[4] = 2.
It should be fairly simple, right? But I can't do it! I keep getting an out of bounds error. This is my code:
int recursoA, recursoB;
dependencias = new int[numberDependencias];
/* I tried setting them all to 0, to see if that was the problem.
* It didn't do anything, as I expected. */
for (int i = 0; i < numberDependencias; i++){
dependencias[i] = 0;
}
int recursoA, recursoB,cont = 0;
while (numberDependencias > 0){
System.out.println("Introduce el primer recurso");
recursoA = Integer.parseInt(br.readLine());
if ((recursoA > 1) && (recursoA <= recursos)){
System.out.println("Introduce el segundo recurso");
recursoB = Integer.parseInt(br.readLine());
dependencias[recursoA] = recursoB; // This is the problem, apparently.
numberDependencias--;
}
Sorry the variables are in Spanish, but hopefully you'll see what I'm talking about. I can't translate it right now.
The integer you're reading-in (recursoA) has to be greater than 1 and less than "recursos". The problem, is that "recursos" is probably greater than "numberDependencias"...which is the max size of your array.
Either alter this line to make sure that recursoA is always less then numberDependencias.
if ((recursoA > 1) && (recursoA < numberDependencias)){
Or, define your array size to be "recursos".
dependencias = new int[recursos];
A Java array has fixed bounds. If you declare it like this:
a = new int[3];
then you can only assign values to a[0], a[1] and a[2]. What you want here is not an array but a Map.
Map<Integer, Integer> dependencias = new HashMap<Integer, Integer>();
dependencias.put(4000, 2000);
dependencias.get(4000) // returns 2000
I suspect the error is being caused by the line:
if ((recursoA > 1) && (recursoA <= recursos)){
What value is recursos being set to? If it is above numberDependencias then an out of bounds error would make sense. Additionally, the open brace at the end of that line doesn't seem to be being closed. This will certainly cause an error!
What values are you trying to introduce for recursoA?
I think you should check if this value is between 0 and numberDependencias-1. Keep in mind that arrays begin at 0, so if you create an array with 4 positions, you can assign values to array[0] ... array[3].
Well I believe what you're saying that you are creating an array that's the size of the number of these "pairs" you have. However, this will give you out of range errors if you have a number larger then the number of pairs, you will get errors. If this is unclear, say you have 2 pairs, (9, 3) and (3, 4), and you try to save them in your array as dependencias[3] = 9 and dependencias[4] = 3. Your going to get errors as dependencias is not large enough for those values to be used as indexes.
To fix this use a Map, which is made like this,
Map<Integer, Integer> dependencias = new HashMap<Integer, Integer>();
then you can add things to your map, like so:
dependencias.put(someInteger1, someInteger2);
Finally you can call back that pair using:
dependencias.get(someInteger1); //this will return someInteger2
Your problem is right here numberDependencias > 0, because you initialze an array with number of elements starting at 0. When you start to fill at numberDependencias, you're try to put in an element out of the arrays size. Try numberDependencias-1 > 0 and use array[numberDependencias] instead of recursoA, excepting you want to initialize your array with recursoA.
Instead of an array I would prefer java.util.HashMap where you can easily put key-value pairs into, besides that you don't need to worry about initializing your size or out of bounds errors.

Categories