How to find the second most frequent character in java?

Viewed 1171

What I am trying to achieve is, when there is a given word, I need to find out the second most frequent character within that string.

In additions to that, there is some more options I want to achieve. For example,

  1. If a string, "ababababd" is given, there are four 'a's, four 'b's, and one 'd', so in this case, I need to printout 'd'.

  2. If a string is "ababababdc" is given, there are four 'a's, four 'b's, one 'd' and 'c', I need to printout 'dc'

    public class MemorizeWorld {
        public static void main(String[] args) {
        Solution solution = new Solution();
        String a = "ababababd";
        solution.solution(a);
     }
    }
    
    class Solution {
         public void solution(String a) {
             int[] array = new int[26];
             char[] char_array = a.toCharArray();
    
             for(int i = 0; i < char_array.length; i++) {
                 int index = char_array[i] - 'a';
                 array[index]++;
             }
             int max = 0;
             for(int i = 0; i < array.length; i++) {
                 if(array[i] > max) {
                     max = array[i];
                 }
             }
         }
     }
    

This is what I have done so far and I am stuck on getting a solution. I know how to get the second most frequent character by following the post from geeksforgeeks, but I don't know how I should apply those two options above to that. Is there anyone who can help me with this problem?

2 Answers

Find the second maximum just like you've found the maximum.

int max2 = 0;
for(int i = 0; i < array.length; i++) {
    if(array[i] > max2 && array[i] < max) {
         max2 = array[i];
     }
}

Then get the result string whose frequency is same as the second maximum.

String result = "";
for(int i = 0; i < array.length; i++) {
    if(array[i] == max2) {
         result += (i + 'a');
     }
}

Stream API may be used in this solution:

  1. create a frequency map using Collectors.groupingBy + Collectors.summingInt / Collectors.counting()
  2. "invert" the frequency and character using Collectors.toMap or Collectors.groupingBy + Collectors.joining to merge characters with the same frequency; use a TreeMap with the reversed key comparator
  3. skip the first value referring the max frequency, and return the next one:
public static String get2ndMostFrequent(String str) {
    if (null == str || str.length() < 2) {
        return null;
    }
    return Arrays.stream(str.split("")) // Stream<String> chars
        .collect(Collectors.groupingBy(
            s -> s, LinkedHashMap::new, Collectors.summingInt(s -> 1)
        ))
        .entrySet()
        .stream()
        .collect(Collectors.toMap(
            Map.Entry::getValue,
            Map.Entry::getKey,
            (s1, s2) -> s1 + s2,
            () -> new TreeMap<Integer, String>(Comparator.reverseOrder())
        ))
        .values()
        .stream()
        .skip(1)
        .findFirst()
        .orElse(null);
}

Tests:

for (String s : Arrays.asList("ababababd", "ababdababc", "dabbcacd", "acbdagh")) {
    System.out.println(s + " -> " + get2ndMostFrequent(s));
}

Output

ababababd -> d
ababdababc -> dc
dabbcacd -> null  // no 2nd frequency
acbdagh -> cbdgh
Related