Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java로 시퀀스에서 두 번째로 많이 반복되는 단어 찾는 방법

Java에서 시퀀스(Sequence)에 담긴 여러 단어 중 두 번째로 많이 반복되는 단어를 찾아야 할 때는 HashMap으로 단어별 등장 횟수를 집계한 뒤, 최빈값과 그다음 값을 순차적으로 추적하는 방식이 효과적입니다. 아래 예제를 통해 구현 방법을 살펴보겠습니다.

예제 코드

import java.util.*;
public class Demo{
    static String second_repeated(Vector<String> my_seq){
        HashMap <String, Integer> my_map = new HashMap<String,Integer>(my_seq.size()){
            @Override
            public Integer get(Object key){
                return containsKey(key) ? super.get(key) : 0;
            }
        };
        for (int i = 0; i < my_seq.size(); i++)
        my_map.put(my_seq.get(i), my_map.get(my_seq.get(i))+1);
        int first_val = Integer.MIN_VALUE;
        int sec_val = Integer.MIN_VALUE;
        Iterator<Map.Entry<String, Integer>> my_iter = my_map.entrySet().iterator();
        while (my_iter.hasNext()){
            Map.Entry<String, Integer> ent = my_iter.next();
            int v = ent.getValue();
            if( v > first_val){
                sec_val = first_val;
                first_val = v;
            }
            else if (v > sec_val && v != first_val)
            sec_val = v;
        }
        my_iter = my_map.entrySet().iterator();
        while (my_iter.hasNext()){
            Map.Entry<String, Integer> ent = my_iter.next();
            int v = ent.getValue();
            if (v == sec_val)
            return ent.getKey();
        }
        return null;
    }
    public static void main(String[] args){
        String arr[] = {"This", "sample", "only", "anything", "sample", "from", "sample","only"};
        List<String> my_seq = Arrays.asList(arr);
        System.out.println("The second most repeated word in the sequence is : ");
        System.out.println(second_repeated(new Vector<>(my_seq)));
    }
}

실행 결과

The second most repeated word in the sequence is :
only

코드 동작 원리

Demo 클래스 안에는 'second_repeated' 함수가 정의되어 있습니다. 이 함수는 해시 맵을 생성하면서 get 메서드를 오버라이드하는데, 일반적인 HashMap은 존재하지 않는 키를 조회할 때 null을 반환하므로, 해당 키가 없으면 null 대신 0을 돌려주도록 처리했습니다. 덕분에 등장 횟수를 누적할 때 별도의 null 검사 없이 코드를 깔끔하게 유지할 수 있습니다.

이후 시퀀스를 처음부터 끝까지 순회하며 각 단어가 몇 번 나타나는지 해시 맵에 하나씩 더해 저장합니다.

집계가 끝나면 entrySet()으로 이터레이터(Iterator)를 만들어 모든 항목을 하나씩 확인하면서, 가장 많이 반복된 횟수(first_val)와 두 번째로 많이 반복된 횟수(sec_val)를 함께 추적합니다. 어떤 값이 현재 최댓값보다 크면 기존 최댓값은 두 번째 값으로 밀려나고 최댓값이 갱신되며, 최댓값은 아니지만 두 번째 값보다 큰 경우에는 두 번째 값만 갱신됩니다.

마지막으로 한 번 더 순회하면서 빈도가 sec_val과 일치하는 첫 번째 단어의 키를 반환하고, 조건에 맞는 단어가 없다면 null을 반환합니다.

main 메서드에는 문자열 배열이 선언되어 있으며, 이 배열은 Arrays.asList()를 통해 리스트로 변환됩니다. 변환된 리스트를 기반으로 Vector를 생성해 'second_repeated' 함수를 호출하면 결과가 콘솔에 출력됩니다. 예제 데이터에서는 "sample"이 3번, "only"가 2번 등장하므로, 두 번째로 많이 반복되는 단어인 only가 화면에 표시됩니다.

참고: 더 간결한 대안

이 알고리즘은 시퀀스를 상수 번 순회하므로 시간 복잡도는 O(n)으로 효율적입니다. 다만 실무에서는 익명 클래스로 get을 오버라이드하는 대신 map.getOrDefault(word, 0) + 1을 사용하는 것이 더 간결하며, Java 8 이상에서는 스트림의 Collectors.groupingByCollectors.counting()을 조합하면 동일한 로직을 훨씬 짧은 코드로 구현할 수 있습니다.