4

Suppose I have a HashSet:

[1, 2, 3, 4, 5, 6]

I want to iterate over it in such a way, that for a given sum, say 6, while iterating over the elements, if I find 2 elements in the Set having sum = 6, I want to remove the other one. E. g., if I am iterating over 1, I should remove 5. I was trying to do something like this:

HashSet<Integer> hs = new HashSet(arr);
int sum = 6;
for(int num : hs) {
    if(hs.contains(sum - num)) {
        hs.remove(sum - num);
    }
}

Obviously it throws java.util.ConcurrentModificationException. Another approach is to use iterator but it removes the current element and does not take any other element as parameter. What else can I use?

Update: I know the techniques to use an additional set and all. I just wanted a very optimal solution without increasing the time and space complexity, if that's possible.

clever_bassi
  • 2,392
  • 2
  • 24
  • 43
  • 1
    Add sum-num into a new set (hs2) and do hs.removeAll(hs2) at the end? – JP Moresmau Apr 22 '15 at 16:44
  • I know that approach. Was trying to find something more optimal. Also, I want to remove the element within the for loop only so that I don't even iterate over that element. – clever_bassi Apr 22 '15 at 16:44
  • 1
    Create a `Set` from `ConcurrentHashMap` maybe? It may be overkill but will work as you want/need. – Luiggi Mendoza Apr 22 '15 at 16:48
  • 2
    If your sum is 6 and you have numbers 1 and 5, how do you know whether to remove 1 or 5? – durron597 Apr 22 '15 at 16:52
  • I am. iterating the hashset. If I encounter 1 first, I will just remove the other one i.e. 5. I am doing this because in the end I am printing all the pairs of numbers that sum upto 6. If I dont remove 5, I get the results as 1,5 and 5,1. To remove this duplicacy, I want to stop from iterating 5 if 1 has been iterated already. – clever_bassi Apr 22 '15 at 17:14

2 Answers2

4

Keep a running set of numbers you have found.

This will allow you to have a one-pass solution.

Start with an empty running set, and iterate through your set of numbers. For each element you iterate through, if its sum-compliment is in the set, remove it from the iterator. Otherwise, add it to the running set.

HashSet<Integer> hs = new HashSet(arr);
HashSet<Integer> running = new HashSet();
int sum = 6;
Iterator<Integer> iter = hs.iterator();
while (iter.hasNext()) {
    int num = iter.next();
    if (running.contains(sum - num)) {
        iter.remove();
    } else {
        running.add(num);
    }
}

This code will modify the original HashSet, and both HashSets will contain the same contents at the end of the code block. In this case, it might be better just to use the running set at the end of the code and not modify the original. That will make this code far more flexible and reusable.

Erick Robertson
  • 32,125
  • 13
  • 69
  • 98
  • No, the first number will remain because its compliment is not in the running set. The second number will be removed because the first number is in the running set. – Erick Robertson Apr 22 '15 at 16:56
  • 1
    Oh, of course. +1. You should mention that this method is destructive on the original `HashSet`, and that both `HashSet`s will be the same (with the elements removed) at the end of the loop. – durron597 Apr 22 '15 at 16:58
  • I am aware of this technique but I didn't want to use an additional HashSet just for space considerations. Thanks though. – clever_bassi Apr 22 '15 at 17:17
  • I think you're going to have a problem finding a solution that meets all of your considerations. If one-pass and one set are both requirements, then I'm afraid there isn't a solution. – Erick Robertson Apr 22 '15 at 17:27
2

you can use a sorted list instead. first your sort the numbers in increasing order. then you put 2 iterator one in first element and other in last element. then in each step if the sum of 2 items under iterators are smaller than your desired number you should increase first iterator if its grater you should decrease second iterator and if it's equal to what you want you pick them and increase first and decrease second iterator.

it works faster than the set!

hasan
  • 966
  • 2
  • 13
  • 40