ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프로그래머스 Lv.2) [1차] 뉴스 클러링
    알고리즘/프로그래머스 카카오 2020. 5. 22. 22:47
    반응형

    2018 KAKAO BLIND RECRUITMENT [1차]

    뉴스 클러링

     

    코딩테스트 연습 - [1차] 뉴스 클러스터링

    뉴스 클러스터링 여러 언론사에서 쏟아지는 뉴스, 특히 속보성 뉴스를 보면 비슷비슷한 제목의 기사가 많아 정작 필요한 기사를 찾기가 어렵다. Daum 뉴스의 개발 업무를 맡게 된 신입사원 튜브��

    programmers.co.kr

    풀이

    한 index를 기준으로 다음 Index와 합쳐 하나의 집합을 이루는데, 이 때 알파벳인지를 확인하는 것과 다중집합이 가능하다는 점, 대소문자 차이는 무시하고 같은 원소로 취급한다는 점, 합집합이 0일 때는 1을 리턴한다 이 4가지만 유의하면 되는 문제다.

    처음에 알파벳 집합만 가능하다에서 알파벳을 제외한 글자는 제거하고 집합을 구해줬더니, 생기면 안되는 집합이 생기는 문제가 있었다.

    그래서 index를 각각 돌면서 체크하는 방식으로 바꿔주었다.

    그 다음에는 다중집합이 가능하다에서 어떻게 해야하는지 고민이 많았다. 그래서 문자열에 대해 각각 HashMap을 만들어서 두글자로 만들어진 집합에 대해 각각 몇 개인지 체크했다.

    이후 발생한 문제는 합집합이 0인 경우였다. 답을 double형으로 구하고 int형으로 형 변환을 할 때 가지는 문제를 제대로 핸들링하지 못했었다. 그래서 그냥 합집합의 총 개수를 세주어 0개일 때, 유사도를 1로 설정해주어 문제를 풀었다.

     

    로직

    1. 문자열 str1,과 str2에 대해 각각 집합을 구해준다.

     1-1. 각각 집합을 구할 때, 다중 집합을 고려해 HashMap을 통해 해당 부분 집합이 몇 번 등장하는지 저장해줬다.

    2. 두 문자열의 집합들에 대해 합집합과 교집합을 구해준다.

    3. 합집합과 교집합을 구한다.

     3-1. 이 때, 합집합과 교집합의 수를 각각 연산한다.

     3-2. 합집합이 0이라면 유사도는 1로 세팅한다.

    4. 유사도에 65536을 곱한 후, int형으로 리턴한다.

     

    코드

    import java.util.ArrayList;
    import java.util.HashMap;
    
    class Solution {
        final static int MULTIPLYING = 65536;
        public int solution(String str1, String str2) {
            return getSimilarity(str1, str2);
        }
        
        private int getSimilarity(String str1, String str2) {
            ArrayList<String> str1List = makeUnion(str1);
            ArrayList<String> str2List = makeUnion(str2);
    
            HashMap<String,Integer> str1Map = new HashMap();
            HashMap<String,Integer> str2Map = new HashMap();
    
            ArrayList<String> unionList = new ArrayList<>();
            ArrayList<String> intersectionList = new ArrayList<>();
    
            setLists(str1List,str1Map,str2List,unionList,intersectionList);
            setLists(str2List,str2Map,str1List,unionList,intersectionList);
    
            int union = 0;
            for(String str : unionList) {
                if(str1Map.containsKey(str)) { // 1만
                    if(str2Map.containsKey(str)) {  // 둘 다
                        union += Math.max(str1Map.get(str),str2Map.get(str));
                    } else {
                        union += str1Map.get(str);
                    }
                } else if(str2Map.containsKey(str)) { // 2만
                    union += str2Map.get(str);
                }
            }
            int intersection =0;
            for(String str : intersectionList) {
                intersection += Math.min(str1Map.get(str), str2Map.get(str));
            }
            double similiarity = (double)intersection/union;
            if(union ==0) { // 합집합이 0인 경우
                similiarity =1.0;
            }
    
            similiarity *= MULTIPLYING;
            return (int)(similiarity);
        }
        
        private static void setLists(ArrayList<String> origin, HashMap<String, Integer> strMap,ArrayList<String> target, ArrayList<String> unionList, ArrayList<String> intersectionList) {
            for(String str : origin) {
                if(!unionList.contains(str)) {
                    unionList.add(str);
                }
                if(!intersectionList.contains(str) && target.contains(str)) {
                    intersectionList.add(str);
                }
                if(!strMap.containsKey(str)) {
                    strMap.put(str,1);
                } else {
                    strMap.replace(str, strMap.get(str)+1);
                }
            }
        }
        
        private ArrayList<String> makeUnion(String str) {
            ArrayList<String> result = new ArrayList<>();
            StringBuffer sb = new StringBuffer();
            
            for(int i=0; i<str.length()-1; i++) {
                char left = str.charAt(i);
                char right = str.charAt(i+1);
                
                if(isChar(left) && isChar(right)) { // 글자
                    if(left >=97) { // 소문자 -> 대문자
                        left-=32;
                    }
                    if(right >=97) {// 소문자 -> 대문자
                        right-=32;
                    }
                    sb.append(left).append(right);
                    result.add(sb.toString());
                    sb.setLength(0);
                }
                
            }
            return result;
        }
        
        private boolean isChar(char ch) {
            return (ch >=65 && ch<=90) || (ch>=97 && ch<=122) ? true : false;
        }
    }
    반응형

    댓글

Designed by Tistory.