2

The task is to write a code which counts the most common number. For example A[1,2,4,4,4,5,6,7,4] would be 4 with 4 counts. I need to keep this code simple because I just tried to implement my code from algorithm and data structure to java.

My idea was this but somehow I never reach the last condition.

public class countingNumbers{

     public static void main(String []args){
         System.out.print(counting(new int[]{1,1,1,2,3,4,4,4,4,5,6}));
     }

     public static int counting(int[] x){
         int memory = 0; 
         int counter = 0;
         int mostCommon = 0;
         for(int i = 0; i < x.length-1;i++){
             for(int j = i+1; j < x.length-1; j++){
                 if(x[i] == x[j]){
                     counter = counter +1;

                 }
                 else if(j == x.length-1 && counter >= memory){
                     mostCommon = x[i];
                     memory = counter;
                     counter = 0;


                 }
             }
         }
         return  mostCommon;
     }
}

-> Thanks in advance for all your answers, I appreciate that. I'am just looking for the logic not for stream, api's or whatever. I tried do handwrite the code and the implementation in java is only for myself to see if it worked out but unfortunately it doesn't.

Update - the right Solution is this:

public class countingNumbers{

 public static void main(String []args){
     System.out.print(counting(new int[]{1,2,2,2,6,2}));
 }

 public static int counting(int[] x){
     int memory = 0; 
     int counter = 1;
     int mostCommon = 0;
     for(int i = 0; i < x.length;i++){
         for(int j = i+1; j <= x.length-1; j++){
             if(x[i] == x[j]){
                 counter = counter + 1;

             }
             if(j == x.length-1 && counter >= memory){
                 mostCommon = x[i];
                 memory = counter;
                 counter = 1;


             }
         }counter = 1;
     } return memory;


 }

}

  • Can you explain the logic you are attempting to implement? If your logic is wrong, a perfect implementation of it isn't worth much; if your logic is OK, then one can focus on the implementation. – Scott Hunter Feb 20 '19 at 17:32
  • 1
    `x.length-1` should be `x.length`. Also, the logic inside the `else-if` can be outside of the inner loop – jrook Feb 20 '19 at 17:33
  • you should only need one loop here with a sorted array. – achAmháin Feb 20 '19 at 17:33
  • So I got this problem now. I put in: {1,2,4,4,5,6,4,4,4} and get memory = 5 If I add one more 4, so: {1,2,4,4,5,6,4,4,4,4} I'll get memory = 7 If I add even three more 4s I get memory = 11; Just really don't know why ... – error404notFound Feb 20 '19 at 18:10
  • What's the expected range for any one element in the array? – גלעד ברקן Feb 20 '19 at 22:04

4 Answers4

4

I'd stream the array and collect it in to a map the counts the occurrences of each element, and then just return the one with the highest count:

/**
 * @return the element that appears most in the array.
 * If two or more elements appear the same number of times, one of them is returned.
 * @throws IllegalArgumentException If the array is empty
 */
public static int counting(int[] x){
    return Arrays.stream(x)
                 .boxed()
                 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                 .entrySet()
                 .stream()
                 .max(Map.Entry.comparingByValue())
                 .map(Map.Entry::getKey)
                 .orElseThrow(() -> new IllegalArgumentException("x must not be empty"));
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
2

If you are good with stream api.. or just for educational goals there is stream solution with groupingBy:

Integer[] arr = {1, 1, 1, 2, 3, 4, 4, 4, 4, 5, 6};

Map<Integer, Long> map = Arrays.stream(arr)
        .collect(Collectors.groupingBy(o -> o, Collectors.counting()));

Integer common = map.entrySet().stream()
        .max(Comparator.comparingLong(Map.Entry::getValue))
        .map(Map.Entry::getKey).get();

System.out.println(common);

Update: If stream is not relevant for you:

It can be done by foor-loop but still it's quite convenient to use Map here:

public static int counting(int[] x) {
    Map<Integer, Long> map = new HashMap<>(); // key is a number, value is how often does it appear in the array 
    for (int number : x) {
        if (map.get(number) != null) {
            map.put(number, map.get(number) + 1);
        } else {
            map.put(number, 1L);
        }
    }
    return Collections.max(map.entrySet(), Map.Entry.comparingByKey()).getKey();
}

Note: there are many ways to get key from map associated with max value. See here to find the most suitable way: Finding Key associated with max Value in a Java Map

Also if else statement can be replaced by merge method from java8:

map.merge(number, 1L, (a, b) -> a + b);
Ruslan
  • 6,090
  • 1
  • 21
  • 36
  • I believe OP wants to know the key, not the value. Your example only works because there are four `4`s, and `4` happens to be most the frequent element in the array. – Jacob G. Feb 20 '19 at 17:38
  • so a stream is not relevant for me. I just need to figure out how it works with simple operators – error404notFound Feb 20 '19 at 17:56
1

Take a look at these two lines:

 for (int j = i + 1; j < x.length - 1; j++) {

and

} else if (j == x.length - 1 && counter >= memory)

You loop while j is strictly less than x.length - 1, but your else if only triggers when j is exactly equal to x.length - 1. So you can never hit the code in your else if block.

Also, your counter should really start at one, since you're counting the number of entries that match the one you're looking at, so you skip counting the first one. But since you're not outputting the counter anywhere, it's not terribly relevant I guess.

So to fix your code, change your inner for loop to go to j <= x.length - 1.

Jordan
  • 2,273
  • 9
  • 16
  • I tried it out but its not working. Sometimes it shows the right number / the right amount of numbers but if i put them in different orders the code isn't working at all – error404notFound Feb 20 '19 at 17:55
  • What specific order are you using that isn't working? – Jordan Feb 20 '19 at 18:47
  • So its working almost. I adopted the changes you mentioned but I got this problem now. I put in: {1,2,4,4,5,6,4,4} and get memory = 4 which is right. If I add one more 4 or to say it generalized if i add the same numbers more than four times I the outcome is not the one it should be. For example if I put in 5 x 4 - the memory = 6. If I put 6 x 4 - the memory is 8 and so on – error404notFound Feb 20 '19 at 19:03
  • Ah, I just noticed a serous bug in the code. You only update `memory` if the last element in the array is *not* the same as the current element that you're counting, since it's in an `else if` block. Get rid of the else and just make it a second if block, and you should get the desired results. – Jordan Feb 20 '19 at 20:30
0

Declare two variables to hold the most common number and its frequency:

int mostCommon =Integer.MIN_VALUE;

int highFreq = 0;

Itereate over your array. For each element iterate over your array again and count its frequency. If current count is greater than highFreq update mostCommon by seting it to current element and set highFreq current count. Example:

public class countingNumbers{

    public static void main(String[] args) {
        int[] res = counting(new int[]{6, 4, 5, 4, 5, 6, 4, 3, 2});
        System.out.println("most common number is: " + res[0] + " with " + res[1] + " counts");
    }

    public static int[] counting(int[] x) {
        int mostCommon = Integer.MIN_VALUE;
        int highFreq = 0;
        for (int i = 0; i < x.length; i++) {
            int currFreq = 0;
            for (int j = 0; j < x.length; j++) {
                if (x[i] == x[j]) {
                    currFreq++;
                }
            }
            if (highFreq < currFreq) {
                highFreq = currFreq;
                mostCommon = x[i];
            }
        }
        return new int[]{mostCommon, highFreq};
    }
}
Eritrean
  • 15,851
  • 3
  • 22
  • 28