Reputation: 617
I am attempting to find how many pairs of values in a given array of integers sum to a specified value k. The logic works if the list contains duplicate values, provided each value has only one complement in the list to sum to k. The issue is that if multiple complements to a given value exist in the list, only one match is counted.
What I have attempted so far is as follows:
int numberOfWays(int[] arr, int k) {
// Write your code here
int output = 0;
HashMap<Integer, Integer> map = new HashMap();
for(int i = 0; i < arr.length; i++) {
int complement = k - arr[i];
if(map.containsKey(complement)) {
output++;
}
map.put(arr[i],i);
System.out.println(map);
}
return output;
}
This works for a case as such: k = 6, arr = [1, 2, 3, 4, 3] However, it doesn't work when there are more than two duplicates: k = 6, arr = [1, 5, 3, 3, 3]
For the case that doesn't work the expected result is 4 but the actual is 3.
I can't seem to figure out why that's the case. Any ideas?
Upvotes: 1
Views: 1255
Reputation: 1430
The reason it didn't work for the second one is, 3 should match 2 other 3s. But map only supports one. The change should be:
int numberOfWays(int[] arr, int k) {
// Write your code here
int output = 0;
HashMap<Integer, Integer> map = new HashMap();
for(int i = 0; i < arr.length; i++) {
int complement = k - arr[i];
int count = map.getOrDefault(arr[i], 0);
if(map.containsKey(complement)) {
count = map.get(complement);
output = output + count; // 2 3s, should match twice.
}
map.put(arr[i], count + 1);
System.out.println(map);
}
return output;
}
Upvotes: 4
Reputation: 40057
Another solution. It works on three principles.
k
that are even, and arr[i] == k/2
the count is (v(v-1)/2
where v
8
and the array contains four 4's
, then the count, v
would be 4
and the sum combinations would be 6
.k = 8
and there are three 3's
and two 5's
the combinations would be three x two == 6
.k
static int numberOfWays(int[] arr, int k) {
int count = 0;
Map<Integer, Integer> map = new HashMap<>();
// accumulate a frequency count values
for (int i = 0; i < arr.length; i++) {
map.compute(arr[i], (key, val) -> val == null ? 1 : val + 1);
}
System.out.println(map);
// copy keys to list for iteration to avoid
// concurrent mod exception when removing keys from
// map. This works better than using an iterator.
List<Integer> keys = new ArrayList<>(map.keySet());
for (int key : keys) {
if ((k&1) == 0 && map.containsKey(key) && key == k/2) {
int v = map.get(key) - 1;
count = count + ((v * (v + 1)) / 2);
} else if (map.containsKey(k-key)) {
System.out.println("trying");
count += (map.get(key) * map.get(k - key));
}
map.remove(key);
}
return count;
}
Upvotes: 0