[JAVA/프로그래머스] 2018 KAKAO BLIND RECRUITMENT: [1차] 뉴스 클러스터링

👀 문제

https://programmers.co.kr/learn/courses/30/lessons/17677

👊 도전

1. 설계

  1. str를 소문자로 변환한다.
  2. for문으로 문자열을 두 글자씩 끊어서 ArrayList에 저장한다.
  3. list1 원소가 list2에 존재하면, 그 원소는 교집합이므로 inter에 넣고, list2에서는 뺀다.
  4. inter.size()가 교집합 개수이고, list1.size()+list2.size()가 합집합이 된다.
  5. 자카드 유사도를 리턴한다.

2. 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.util.*;
/**
 *
 * @author HEESOO
 *
 */
class Solution {
    public int solution(String str1, String str2) {
        int answer = 0;
        // 소문자 변환
        str1=str1.toLowerCase();
        str2=str2.toLowerCase();
        
        // 두 글자씩 끊어서 저장
        ArrayList<String> list1=splitTwoWord(str1);
        ArrayList<String> list2=splitTwoWord(str2);
        Collections.sort(list1);
        Collections.sort(list2);
        
        ArrayList<String> inter=new ArrayList<>(); // 교집합
        for(String s:list1){
            if(list2.contains(s)){ // 교집합 원소
                inter.add(s);
                list2.remove(s);
            }
        }
        
        double union=list1.size()+list2.size(); // 합집합 개수
        if(union==0) answer=65536; // division by zero 예외처리
        else answer=(int)(inter.size()/union*65536);
        return answer;
    }
    
    public ArrayList<String> splitTwoWord(String str){
        // for문으로 i, i+1을 result에 저장
        ArrayList<String> result=new ArrayList<>();
        for(int i=0;i<str.length()-1;i++){
            // 둘 다 알파벳인지 체크
            if(isAlpha(str.charAt(i)) && isAlpha(str.charAt(i+1)))
                result.add(str.charAt(i)+""+str.charAt(i+1));
        }
        
        return result;
    }
    
    public boolean isAlpha(char ch){ // ch가 알파벳이면 true 리턴
        if('a'<=ch && ch<='z') return true;
        else return false;
    }
}

3. 결과

실행결과 🤟 성공 🤟

4. 설명

  1. 두 글자씩 끊어서 ArrayList에 저장한다
    • 대문자, 소문자 차이는 무시하므로 맨 처음에 toLowerCase()로 str를 모두 소문자로 바꾼다.
    • splitTwoWord()로 i, i+1이 모두 영문자라면 두 char형을 String으로 합쳐 result에 넣는다.
    • 영문자인지 체크하는 것은 isAlpha()를 이용한다.
    • 두 글자씩 끊은 문자열은 중복이 허용되므로 Hash를 이용할 수 없다.
    • 뒤에서 교집합을 찾는 것이 좀 더 수월하도록 오름차순 정렬하였다.
  2. 교집합을 구한다
    • list1의 원소가 list2에 존재하는지 contains()로 확인한다.
    • 존재한다면 그 원소는 교집합 원소가 될 수 있으므로 inter에 넣고, list2에서는 제거한다.
    • list2에서 교집합 원소를 빼고 최종적으로 B-A(차집합) 원소들만 남게 할 것이다.
  3. 자카드 유사도를 구한다
    • for문으로 교집합 원소를 구하면, 합집합 개수는 list1.size()+list2.size()이다.
    • str1, str2 집합이 공집합인 경우도 체크해야 한다(테스트4).
    • 테스트4에서 str1, str2은 공집합이 되는데, answer이 65536이 된다는 뜻은 자카드 수가 1이라는 뜻이다. 따라서, union이 0이면 answer은 65536이 되도록 예외 처리한다.

👏 해결 완료!

참고