(1차) 뉴스 클러스터링

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/17677

접근 방식

각각의 문자열을 통합하기 위해, 모두 대문자로 변환한다.

이후 2문자씩 끊어서 모두 대문자에 해당하는지 확인하고, 해당 한다면 문자열을 만들어서 리스트에 추가한다.

그렇게 만들어진 두 개의 리스트를 비교하며, 교집합과 합집합을 구한다.

잘못된 접근

import java.util.*;

class Solution {
    public int solution(String str1, String str2) {
        List<String> a = new ArrayList<>();
        List<String> b = new ArrayList<>();
        str1 = str1.toUpperCase();
        str2 = str2.toUpperCase();
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<str1.length()-1; i++){
            int tmp1 = str1.charAt(i) - 'A';
            int tmp2 = str1.charAt(i+1) - 'A';
            if(tmp1>=0 && tmp1<=25 && tmp2>=0 && tmp2<=25){
                sb.append(str1.charAt(i)).append(str1.charAt(i+1));
                a.add(sb.toString());
                sb.setLength(0);
            }
        }
        sb.setLength(0);
        for(int i=0; i<str2.length()-1; i++){
            int tmp1 = str2.charAt(i) - 'A';
            int tmp2 = str2.charAt(i+1) - 'A';
            if(tmp1>=0 && tmp1<=25 && tmp2>=0 && tmp2<=25){
                sb.append(str2.charAt(i)).append(str2.charAt(i+1));
                b.add(sb.toString());
                sb.setLength(0);
            }
        }
        if(a.isEmpty() && b.isEmpty()) return 65536;
        int commonCnt = compare(a, b); // 교집합
        int sumCnt = a.size()+b.size()-commonCnt; // 합집합
        double answer = (double)commonCnt/(double)sumCnt;
        return (int)(answer*65536);
    }

    int compare(List<String> a, List<String> b){
        int cnt = 0;
        for(int i=0; i<a.size(); i++){
            if(b.contains(a.get(i))) cnt++;
        }

        return cnt;
    }
}

위 방식에는 문제가 있다. 바로 한 개만 가지고 있더라고 가지고 있다고 생각하여 체크한다는 것.

예를 들어, A=(11, 12, 11, 11), B=(11, 11, 13) 과 같이 두 개의 집합이 있다고 했을 때

교집합은 11, 11 두 개만 존재해야 한다. 하지만 현재 로직에서는 세 번째 11을 체크할 때 B 집합에 11이 존재하기 때문에 3번째 11도 교집합에 추가하여
최종 교집합은 (11, 11, 11)이 된다. 따라서 교집합에 추가하면 해당 원소를 제거해야 중복 체크가 발생하지 않는다.

b.remove(a.get(i));

결과

소스 코드

import java.util.*;

class Solution {
    public int solution(String str1, String str2) {
        List<String> a = new ArrayList<>();
        List<String> b = new ArrayList<>();
        str1 = str1.toUpperCase();
        str2 = str2.toUpperCase();
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<str1.length()-1; i++){
            int tmp1 = str1.charAt(i) - 'A';
            int tmp2 = str1.charAt(i+1) - 'A';
            if(tmp1>=0 && tmp1<=25 && tmp2>=0 && tmp2<=25){
                sb.append(str1.charAt(i)).append(str1.charAt(i+1));
                a.add(sb.toString());
                sb.setLength(0);
            }
        }
        sb.setLength(0);
        for(int i=0; i<str2.length()-1; i++){
            int tmp1 = str2.charAt(i) - 'A';
            int tmp2 = str2.charAt(i+1) - 'A';
            if(tmp1>=0 && tmp1<=25 && tmp2>=0 && tmp2<=25){
                sb.append(str2.charAt(i)).append(str2.charAt(i+1));
                b.add(sb.toString());
                sb.setLength(0);
            }
        }
        int answer = 65536;
        if(a.isEmpty() && b.isEmpty()) return answer;
        int sumCnt = a.size()+b.size(); // 합집합
        int commonCnt = a.size()>b.size() ? compare(b,a) :compare(a, b); // 교집합
        sumCnt-=commonCnt;
        answer = (int)(((double)commonCnt/(double)sumCnt)*65536);
        return answer;
    }

    int compare(List<String> a, List<String> b){
        int cnt = 0;
        for(int i=0; i<a.size(); i++){
            if(b.contains(a.get(i))) {
                b.remove(a.get(i));
                cnt++;
            }
        }

        return cnt;
    }
}

다른 접근 방식

없음.

알게 된 점

없음.