Find the element the occurs more than \$\dfrac{n}{2}\$ times in an input array, where \$n\$ is input array length.
I'm looking for code review, optimizations and best practices.
public final class VotingAlgorithm {
// non-instantiable.
private VotingAlgorithm() {}
/**
* Returns the number which occurs more than n/2 times.
* If such a number does not exist, then results are unpredicatable.
*
* @param a the input array
* @return the number occuring more than n/2 times.
*/
public static int maxElement(int[] a) {
int maxElementIndex = 0;
int counter = 1;
for (int i = 1; i < a.length; i++) {
if (a[maxElementIndex] == a[i]) {
counter++;
} else {
counter--;
}
if (counter == 0) {
maxElementIndex = i;
counter++;
}
}
return a[maxElementIndex];
}
public static void main(String[] args) {
int[] a1 = {1, 2, 3, 1, 1, 1};
assertEquals(1, maxElement(a1));
int[] a2 = {2, 3, 1, 1, 1, 1};
assertEquals(1, maxElement(a2));
int[] a3 = {1, 1, 1, 1, 2, 3};
assertEquals(1, maxElement(a3));
int[] a4 = {1, 2, 1, 3, 1, 1};
assertEquals(1, maxElement(a4));
int[] a5 = {1, 2, 3, 4, 1, 1, 1};
assertEquals(1, maxElement(a5));
int[] a6 = {2, 3, 4, 1, 1, 1, 1};
assertEquals(1, maxElement(a6));
int[] a7 = {1, 1, 1, 1, 2, 3, 4};
assertEquals(1, maxElement(a7));
int[] a8 = {1, 2, 1, 3, 1, 4, 1};
assertEquals(1, maxElement(a8));
}
}
2 Answers 2
Your code is very clever, perhaps a little too clever... It almost looks like you wrote the code first, and then asked yourself - what can this achieve?
As @rolfl said - as it is currently written - the code is all but useless, because most of the time the result is unpredictable. Calling this method will return a value, which could either have more than half the length of occurrences, or... not?
You could achieve at least as much information with the same complexity, by keeping more complete score.
Here is an example, where you can save the count of each element, and keep the one with most occurrences:
public int elementWithMostOccurrences(int[] inputArray) {
HashMap<Integer, Integer> occurrenceCount = new HashMap<Integer, Integer>();
int currentMaxElement = inputArray[0];
for (int i = 1; i < inputArray.length; i++) {
Integer elementCount = occurrenceCount.get(inputArray[i]);
if (elementCount != null)) {
occurrenceCount.put(inputArray[i], elementCount + 1);
if (elementCount >= occurrenceCount.get(currentMaxElement)) {
currentMaxElement = inputArray[i];
}
} else {
occurrenceCount.put(inputArray[i], 1);
}
}
// if you want to return the element only if it has more than half the array size you can:
// if (occurrenceCount.get(currentMaxElement) > inputArray.Length / 2) { ... }
return currentMaxElement;
}
This example is also \$O(n)\$ complexity, but gives a valuable result every time.
-
\$\begingroup\$ Even though you have a very good alternative code here, your code is C# while the question is Java. Want some help in translating it to Java? \$\endgroup\$Simon Forsberg– Simon Forsberg2014年03月30日 20:35:58 +00:00Commented Mar 30, 2014 at 20:35
-
\$\begingroup\$ @SimonAndréForsberg - Woops... didn't even notice I switched languages... Thanks for pointing it out... I'm a little rusty with auto-boxing, could you please verify my java version? \$\endgroup\$Uri Agassi– Uri Agassi2014年03月31日 06:35:06 +00:00Commented Mar 31, 2014 at 6:35
-
\$\begingroup\$ Use
HashMap
instead ofHashtable
, and use the.get
and.put
methods of it. You can't access it by indexes directly. besides that, it looks fine. \$\endgroup\$Simon Forsberg– Simon Forsberg2014年03月31日 09:57:45 +00:00Commented Mar 31, 2014 at 9:57
The JavaDoc and the method names do not agree.
The method name maxElement
implies the method will get either:
- the element that occurs most frequenly
- the element with the largest value
This function may, or may not, do both.
The JavaDoc indicates that this function will return the value that occurs more more than half-the-time, and that if there is no such element, the result is undefined.
This makes the method useless, because anyone calling the method will then have to re-scan the entire data set to see whether the method is returning a right answer, or an undefined answer.
Since repeating all the work to check whether the method produced a reliable result or not is required anyway, you may as well do it in the method itself, and then return a result which removes the non-determinism.
int[] a9 = {1, 2, 2, 1, 3, 3, 1, 4, 4, 1, 5, 5, 5};
... what's the result? \$\endgroup\$mightGetMaxElement(...)
\$\endgroup\$