Algorithm/Programmers

[프로그래머스] 2019 KAKAO BLIND RECRUITMENT 매칭 점수 (Java)

728x90

[프로그래머스] 2019 KAKAO BLIND RECRUITMENT 매칭 점수 : https://programmers.co.kr/learn/courses/30/lessons/42893

 

코딩테스트 연습 - 매칭 점수 | 프로그래머스

매칭 점수 프렌즈 대학교 조교였던 제이지는 허드렛일만 시키는 네오 학과장님의 마수에서 벗어나, 카카오에 입사하게 되었다. 평소에 관심있어하던 검색에 마침 결원이 발생하여, 검색개발팀에 편입될 수 있었고, 대망의 첫 프로젝트를 맡게 되었다. 그 프로젝트는 검색어에 가장 잘 맞는 웹페이지를 보여주기 위해 아래와 같은 규칙으로 검색어에 대한 웹페이지의 매칭점수를 계산 하는 것이었다. 한 웹페이지에 대해서 기본점수, 외부 링크 수, 링크점수, 그리고 매칭점수를

programmers.co.kr

 

 

2019 카카오 공채의 6번째 문제 매칭 점수다.

이번 코테에서 가장 어려웠던 문제인 것 같다. 내가 문자열에 많이 약하다는 것을 알게 된 계기가 되었다.

문자열 파싱과 정규표현식 응용하는 것에 대해 공부를 해야겠다.

 

문제가 굉장히 길긴 하지만, 이해하기 크게 어렵진 않다.

웹페이지의 html을 입력받으면 기본점수, 외부 링크 수, 링크 점수, 매칭점수를 구하면 된다.

 

이번 문제에서 구현해야 하는 로직은 다음과 같다. 아래의 순서대로 실행을 하면 된다.

  1. html에서 해당 웹페이지의 url 추출하기. (findUrl 함수)
  2. 검색어(word)가 등장하는 횟수를 체크해서 기본 점수 계산하기. (setDefaultScore 함수)
  3. 한 웹페이지의 외부 링크 수 계산하기. (setLinkCount 함수)
  4. 웹페이지의 링크 점수 계산하기. (setLinkScore 함수)

 

링크 점수를 계산할 때 외부 웹페이지의 url을 바로 찾아야 해서 HashMap을 사용했다.

위의 로직을 모두 수행하면 각각의 웹페이지의 링크 점수가 나온다.

기본점수와 링크 점수의 합으로 정렬을 한 뒤, 가장 큰 값의 웹페이지의 index를 구하면 된다.

 

 

처음엔 정규표현식이 익숙지 않아 사용하지 않고 문자열 파싱을 했는데 굉장히 번거롭고 코드가 난잡해졌다.

도저히 이렇게는 안될 것 같아 정규표현식을 공부한 뒤, 다시 처음부터 구현했다.

문자열 파싱 관련해서 새로운 개념을 많이 공부한 듯해서 풀길 잘했다는 생각이 든다.

당분간은 백준에서 문자열 파싱과 정규표현식 문제를 찾아 풀어봐야겠다.

 

 

총 걸린 시간 : 3시간 이상

난이도 : ★★★★★

 

코드

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Solution {
    private HashMap<String, Page> map = new HashMap<>();

    public int solution(String word, String[] pages) {
        int idx = 0;
        for (String html : pages) {
            Page page = new Page(idx++, html.toLowerCase());
            page.setDefaultScore(word.toLowerCase());
            page.setLinkCount();
            map.put(page.url, page);
        }

        for (Page page : map.values()) {
            page.setLinkScore();
        }

        ArrayList<Page> list = new ArrayList(map.values());
        Collections.sort(list);

        return list.get(0).idx;
    }

    class Page implements Comparable<Page> {
        int idx;
        int defaultScore = 0;
        int linkCount = 0;
        double linkScore = 0;
        String html, url;

        Page(int idx, String html) {
            this.idx = idx;
            this.html = html;
            findUrl();
        }

        private void findUrl() {
            Pattern pattern = Pattern.compile("<meta property=\"og:url\" content=\"https://(.+?)\"/>");
            Matcher matcher = pattern.matcher(html);
            while (matcher.find()) {
                url = matcher.group(1);
            }
        }

        public void setDefaultScore(String word) {
            int idx = html.indexOf(word);
            while (idx != -1) {
                char pre = html.charAt(idx - 1);
                char post = html.charAt(idx + word.length());

                if (!Character.isLowerCase(pre) && !Character.isLowerCase(post)) {
                    defaultScore++;
                }
                idx = html.indexOf(word, idx + 1);
            }
        }

        public void setLinkCount() {
            int idx = html.indexOf("<a href=");
            while (idx != -1) {
                linkCount++;
                idx = html.indexOf("<a href=", idx + 1);
            }
        }

        public void setLinkScore() {
            Pattern pattern = Pattern.compile("<a href=\"https://(.+?)\">");
            Matcher matcher = pattern.matcher(html);
            while (matcher.find()) {
                String externalUrl = matcher.group(1);
                if (map.containsKey(externalUrl)) {
                    map.get(externalUrl).linkScore += (double) defaultScore / linkCount;
                }
            }
        }

        @Override
        public int compareTo(Page other) {
            double a = (double) this.defaultScore + this.linkScore;
            double b = (double) other.defaultScore + other.linkScore;

            return Double.compare(b, a);
        }
    }
}
728x90