Home » Java » java – Problem finding duplicate numbers in array, is my technique bad?-Exceptionshub

java – Problem finding duplicate numbers in array, is my technique bad?-Exceptionshub

Posted by: admin February 25, 2020 Leave a comment

Questions:

I used a HashMap to store the occurrences of each element, and then iterated over the hash map to get duplicated element, but something doesn’t feel right about this solution.

Problem statement in Firecode.io:

Write a method duplicate to find the repeated or duplicate elements in an array. This method should return a list of repeated integers in a string with the elements sorted in ascending order (as illustrated below).

duplicate({1,3,4,2,1}) –> "[1]"

duplicate({1,3,4,2,1,2,4}) –> "[1, 2, 4]"

Note: You may use toString() method to return the standard string representation of most data structures, and Arrays.sort() to sort your result.*

Here is my code:

 public String duplicate(int[] numbers) {
      HashMap < Integer, Integer > hs = new HashMap < Integer, Integer > ();
      for (int i = 0; i < numbers.length; i++) {
           if (hs.get(numbers[i]) == null) {
                hs.put(numbers[i], 1);
           } else hs.put(numbers[i], (Integer) hs.get(numbers[i]) + 1);
      }

      int size = 0;
      for (int i: hs.keySet()) {
           if (hs.get(i) > 1) {
                size++;
           }
      }
      int j = 0;
      int[] a = new int[size];
      for (int i: hs.keySet()) {
           if (hs.get(i) > 1) {
                a[j++] = i;
           }
      }

      Arrays.sort(a);
      return Arrays.toString(a);
 }
How to&Answers:

Here’s the way I would do it: (comments for educational purposes, would probably not have them in production code.)

public String duplicate(int[] numbers) {

  // holds the items we've encountered more than once.
  // TreeSet<> keeps things in sorted order for us.
  final SortedSet<Integer> duplicates = new TreeSet<>();

  // keeps track of items we've encountered.
  final Set<Integer> encountered = new HashSet<>(); 

  // iterate over every number
  for (final int number : numbers) {
    // Add the item to encountered. Set.add() will return true if 
    // the element is new to the set.
    if (!encountered.add(number)) {
       // Since the element wasn't new, ensure this item exists in the duplicates collection.
       duplicates.add(number);
    }
  }

  return duplicates.toString();
}

Answer:

Since you don’t have to tell how many times an element is duplicated you only need a Set to remember which elements are unique and which not. If you know the element values (e.g. numbers between 1 and 10) you could further simplify Set to boolean[] or a bit vector:

int[] numbers = {1, 3, 4, 2, 2, 1, 2, 4, 4};
Set<Integer> unique = new HashSet<>();
Set<Integer> duplicates = new HashSet<>();
for (int n : numbers) {
    if (!unique.add(n)) {
        duplicates.add(n);
    }
}
List<Integer> result = new ArrayList<>(duplicates);
result.sort(Integer::compareTo);
System.out.println(result); // [1, 2, 4]

Answer:

You do not need another loop to get the value of size.

Replace

HashMap < Integer, Integer > hs = new HashMap < Integer, Integer > ();
for (int i = 0; i < numbers.length; i++) {
   if (hs.get(numbers[i]) == null) {
        hs.put(numbers[i], 1);
   } else hs.put(numbers[i], (Integer) hs.get(numbers[i]) + 1);
}

int size = 0;
for (int i: hs.keySet()) {
   if (hs.get(i) > 1) {
        size++;
   }
}

with

HashMap < Integer, Integer > hs = new HashMap < Integer, Integer > ();
int size=0;
for (int i = 0; i < numbers.length; i++) {
   if (hs.get(numbers[i]) == null) {
        hs.put(numbers[i], 1);
   } else {
        hs.put(numbers[i], (Integer) hs.get(numbers[i]) + 1);
        size++;
   }
}

Answer:

If you are using Java 8 or beyond you can try:

public String duplicate(int[] numbers) {
    Map<Integer, Integer> hs = new HashMap<>();
    for ( int i : numbers ) {
        hs.merge( i, 1, Integer::sum);
    }
    return '[' + 
             hs.entrySet()
               .stream()
               .filter( e -> e.getValue() > 1 )
               .map(Entry::getKey)
               .sorted()
               .map(i -> i.toString())
               .collect(Collectors.joining(", ")) +
           ']';
}