[프로그래머스] 매칭 점수 / Java

2021. 3. 24. 11:03·Programmers
반응형

문제주소 :programmers.co.kr/learn/courses/30/lessons/42893

 

코딩테스트 연습 - 매칭 점수

매칭 점수 프렌즈 대학교 조교였던 제이지는 허드렛일만 시키는 네오 학과장님의 마수에서 벗어나, 카카오에 입사하게 되었다. 평소에 관심있어하던 검색에 마침 결원이 발생하여, 검색개발팀

programmers.co.kr


<문제 설명>

더보기

문제 설명

매칭 점수

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

  • 한 웹페이지에 대해서 기본점수, 외부 링크 수, 링크점수, 그리고 매칭점수를 구할 수 있다.
  • 한 웹페이지의 기본점수는 해당 웹페이지의 텍스트 중, 검색어가 등장하는 횟수이다. (대소문자 무시)
  • 한 웹페이지의 외부 링크 수는 해당 웹페이지에서 다른 외부 페이지로 연결된 링크의 개수이다.
  • 한 웹페이지의 링크점수는 해당 웹페이지로 링크가 걸린 다른 웹페이지의 기본점수 ÷ 외부 링크 수의 총합이다.
  • 한 웹페이지의 매칭점수는 기본점수와 링크점수의 합으로 계산한다.

예를 들어, 다음과 같이 A, B, C 세 개의 웹페이지가 있고, 검색어가 hi라고 하자.

이때 A 웹페이지의 매칭점수는 다음과 같이 계산할 수 있다.

  • 기본 점수는 각 웹페이지에서 hi가 등장한 횟수이다.
    • A,B,C 웹페이지의 기본점수는 각각 1점, 4점, 9점이다.
  • 외부 링크수는 다른 웹페이지로 링크가 걸린 개수이다.
    • A,B,C 웹페이지의 외부 링크 수는 각각 1점, 2점, 3점이다.
  • A 웹페이지로 링크가 걸린 페이지는 B와 C가 있다.
    • A 웹페이지의 링크점수는 B의 링크점수 2점(4 ÷ 2)과 C의 링크점수 3점(9 ÷ 3)을 더한 5점이 된다.
  • 그러므로, A 웹페이지의 매칭점수는 기본점수 1점 + 링크점수 5점 = 6점이 된다.

검색어 word와 웹페이지의 HTML 목록인 pages가 주어졌을 때, 매칭점수가 가장 높은 웹페이지의 index를 구하라. 만약 그런 웹페이지가 여러 개라면 그중 번호가 가장 작은 것을 구하라.

제한사항

  • pages는 HTML 형식의 웹페이지가 문자열 형태로 들어있는 배열이고, 길이는 1 이상 20 이하이다.
  • 한 웹페이지 문자열의 길이는 1 이상 1,500 이하이다.
  • 웹페이지의 index는 pages 배열의 index와 같으며 0부터 시작한다.
  • 한 웹페이지의 url은 HTML의 <head> 태그 내에 <meta> 태그의 값으로 주어진다.
    • 예를들어, 아래와 같은 meta tag가 있으면 이 웹페이지의 url은 https://careers.kakao.com/index 이다.
    • <meta property="og:url" content="https://careers.kakao.com/index" />
  • 한 웹페이지에서 모든 외부 링크는 <a href="https://careers.kakao.com/index"\>의 형태를 가진다.
    • <a> 내에 다른 attribute가 주어지는 경우는 없으며 항상 href로 연결할 사이트의 url만 포함된다.
    • 위의 경우에서 해당 웹페이지는 https://careers.kakao.com/index 로 외부링크를 가지고 있다고 볼 수 있다.
  • 모든 url은 https:// 로만 시작한다.
  • 검색어 word는 하나의 영어 단어로만 주어지며 알파벳 소문자와 대문자로만 이루어져 있다.
  • word의 길이는 1 이상 12 이하이다.
  • 검색어를 찾을 때, 대소문자 구분은 무시하고 찾는다.
    • 예를들어 검색어가 blind일 때, HTML 내에 Blind라는 단어가 있거나, BLIND라는 단어가 있으면 두 경우 모두 해당된다.
  • 검색어는 단어 단위로 비교하며, 단어와 완전히 일치하는 경우에만 기본 점수에 반영한다.
    • 단어는 알파벳을 제외한 다른 모든 문자로 구분한다.
    • 예를들어 검색어가 "aba" 일 때, "abab abababa"는 단어 단위로 일치하는게 없으니, 기본 점수는 0점이 된다.
    • 만약 검색어가 "aba" 라면, "aba@aba aba"는 단어 단위로 세개가 일치하므로, 기본 점수는 3점이다.
  • 결과를 돌려줄때, 동일한 매칭점수를 가진 웹페이지가 여러 개라면 그중 index 번호가 가장 작은 것를 리턴한다
    • 즉, 웹페이지가 세개이고, 각각 매칭점수가 3,1,3 이라면 제일 적은 index 번호인 0을 리턴하면 된다.

입출력 예 #1

  • word : blind
  • pages :
  • ["<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n <meta charset=\"utf-8\">\n <meta property=\"og:url\" content=\"https://a.com\"/>\n</head> \n<body>\nBlind Lorem Blind ipsum dolor Blind test sit amet, consectetur adipiscing elit. \n<a href=\"https://b.com\"> Link to b </a>\n</body>\n</html>", "<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n <meta charset=\"utf-8\">\n <meta property=\"og:url\" content=\"https://b.com\"/>\n</head> \n<body>\nSuspendisse potenti. Vivamus venenatis tellus non turpis bibendum, \n<a href=\"https://a.com\"> Link to a </a>\nblind sed congue urna varius. Suspendisse feugiat nisl ligula, quis malesuada felis hendrerit ut.\n<a href=\"https://c.com\"> Link to c </a>\n</body>\n</html>", "<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n <meta charset=\"utf-8\">\n <meta property=\"og:url\" content=\"https://c.com\"/>\n</head> \n<body>\nUt condimentum urna at felis sodales rutrum. Sed dapibus cursus diam, non interdum nulla tempor nec. Phasellus rutrum enim at orci consectetu blind\n<a href=\"https://a.com\"> Link to a </a>\n</body>\n</html>"]
  • pages는 다음과 같이 3개의 웹페이지에 해당하는 HTML 문자열이 순서대로 들어있다.

Blind Lorem Blind ipsum dolor Blind test sit amet, consectetur adipiscing elit. Link to b

Suspendisse potenti. Vivamus venenatis tellus non turpis bibendum, Link to a blind sed congue urna varius. Suspendisse feugiat nisl ligula, quis malesuada felis hendrerit ut. Link to c

Ut condimentum urna at felis sodales rutrum. Sed dapibus cursus diam, non interdum nulla tempor nec. Phasellus rutrum enim at orci consectetu blind Link to a

위의 예를 가지고 각각의 점수를 계산해보자.

  • 기본점수 및 외부 링크수는 아래와 같다.
    • a.com의 기본점수는 3, 외부 링크 수는 1개
    • b.com의 기본점수는 1, 외부 링크 수는 2개
    • c.com의 기본점수는 1, 외부 링크 수는 1개
  • 링크점수는 아래와 같다.
    • a.com의 링크점수는 b.com으로부터 0.5점, c.com으로부터 1점
    • b.com의 링크점수는 a.com으로부터 3점
    • c.com의 링크점수는 b.com으로부터 0.5점
  • 각 웹 페이지의 매칭 점수는 다음과 같다.
    • a.com : 4.5 점
    • b.com : 4 점
    • c.com : 1.5 점

따라서 매칭점수가 제일 높은 첫번째 웹 페이지의 index인 0을 리턴 하면 된다.

입출력 예 #2

  • word : Muzi
  • pages :
  • ["<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n <meta charset=\"utf-8\">\n <meta property=\"og:url\" content=\"https://careers.kakao.com/interview/list\"/>\n</head> \n<body>\n<a href=\"https://programmers.co.kr/learn/courses/4673\"></a>#!MuziMuzi!)jayg07con&&\n\n</body>\n</html>", "<html lang=\"ko\" xml:lang=\"ko\" xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n <meta charset=\"utf-8\">\n <meta property=\"og:url\" content=\"https://www.kakaocorp.com\"/>\n</head> \n<body>\ncon%\tmuzI92apeach&2<a href=\"https://hashcode.co.kr/tos\"></a>\n\n\t^\n</body>\n</html>"]
  • pages는 다음과 같이 2개의 웹페이지에 해당하는 HTML 문자열이 순서대로 들어있다.

#!MuziMuzi!)jayg07con&&

con% muzI92apeach&2 ^

  • 기본점수 및 외부 링크수는 아래와 같다.
    • careers.kakao.com/interview/list 의 기본점수는 0, 외부 링크 수는 1개
    • www.kakaocorp.com 의 기본점수는 1, 외부 링크 수는 1개
  • 링크점수는 아래와 같다.
    • careers.kakao.com/interview/list 의 링크점수는 0점
    • www.kakaocorp.com 의 링크점수는 0점
  • 각 웹 페이지의 매칭 점수는 다음과 같다.
    • careers.kakao.com/interview/list : 0점
    • www.kakaocorp.com : 1 점

따라서 매칭점수가 제일 높은 두번째 웹 페이지의 index인 1을 리턴 하면 된다.

 

<풀이법>

▒ 한줄 개념: 정규식 ▒ 

정규식을 이용하여 문자열을 파싱하고, 그 데이터를 사용하여 푸는 문제이다.

문제풀이 과정은 다음과 같다.

 

1. Link 객체 구현:

기본점수, 외부 링크들, 링크 점수, 인덱스를 가지는 Link 클래스를 만들어주었다.

 

2. 자기 자신의 url 링크 추출: 

Pattern home_url_pattern = Pattern.compile("<meta property=\"og:url\" content=\"(\\S*)\"");

위 정규식을 이용하여 자기 자신의 url을 추출해주었다. 이 url을 기반으로 새로운 Link 객체를 생성한다.

 

3. 연결된 외부 링크들 추출:

Pattern url_pattern = Pattern.compile("<a href=\"https://(\\S*)\"");

위 정규식을 이용하여 연결된 외부 링크들을 추출해준다. 추출한 외부 링크들을 Link 객체의 외부 링크들 변수에 차례차례 넣어준다.

 

4. word 등장 횟수(기본점수) 계산:

숫자, 특수문자 등 알파벳이 아닌 모든 문자가 각 단어 사이의 구분자가 된다.

body = pages[i].split("<body>")[1].split("</body>")[0].replaceAll("[0-9]", " ");  

Pattern word_pattern = Pattern.compile("\\b(?i)"+word+"\\b");

따라서 편의를 위해 <body> 태그 내 모든 숫자를 공백(" ")으로 replace해주었다. 따라서 단어를 검색하는 정규식이 양쪽에 특수문자가 존재하는지만 판별하면 되므로, 단순화되었다. (?i)는 대소문자 구분을 하지 않도록 하기 위해 넣어주었다.

 

5. 링크점수 계산:

각 페이지에서 자신의 외부 링크에 대해 링크점수를 더해준다. 페이지 A에서 페이지 B로 자신의 기본점수 / 외부 링크 수의 점수를 보내준다고 생각하면 된다.

 

6. 총점(매칭점수)가 가장 높은 페이지 확인:

단순 반복문을 사용해 max값을 가진 페이지를 찾으면 된다.

 

 

<주의사항>

url을 검사할때, https:// 검색에서 (.*)을 사용할 때는 55점에서 머물렀는데,(\\S*)를 사용하니 100점으로 통과되었다. 이유는 잘 모르겠다. 공부가 더 필요할 것 같다.

 

 

<코드(Java)>

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Solution {
    HashMap<String, Link> Links;
        public int solution(String word, String[] pages) {
            Links = new HashMap<>();

            Pattern home_url_pattern = Pattern.compile("<meta property=\"og:url\" content=\"(\\S*)\"");
            Pattern url_pattern = Pattern.compile("<a href=\"https://(\\S*)\"");
            Pattern word_pattern = Pattern.compile("\\b(?i)"+word+"\\b");
            Matcher url_matcher, word_matcher, home_url_matcher;

            ArrayList<String> ext_urls;
            Link new_Link;
            String body;
            String home_url = "";

            for(int i = 0; i < pages.length; i++){
                url_matcher = url_pattern.matcher(pages[i]);
                home_url_matcher = home_url_pattern.matcher(pages[i]);

                if(home_url_matcher.find()){
                    home_url = home_url_matcher.group().split("=")[2].replaceAll("\"", "");
                }
                
                new_Link = new Link(i, home_url);
                
                ext_urls = new ArrayList<>();

                while(url_matcher.find()) {
                    ext_urls.add(url_matcher.group().split("\"")[1]);
                }
                new_Link.setExtUrls(ext_urls);
                
                
                body = pages[i].split("<body>")[1].split("</body>")[0].replaceAll("[0-9]", " ");            
                word_matcher = word_pattern.matcher(body);
                int word_cnt = 0;
                while(word_matcher.find())
                    word_cnt++;

                new_Link.point = word_cnt;
                new_Link.setLinkPoint();

                Links.put(new_Link.url, new_Link);
            }

            for(Link link: Links.values()){
                for(String ext_url : link.ext_urls){
                    if(Links.containsKey(ext_url)){
                        Links.get(ext_url).point += link.link_point;
                    }
                }
            }

            double max_point = 0;
            int answer = 0;
            for(Link link: Links.values()){
                if(link.point == max_point){
                    if(link.index < answer)
                        answer = link.index;
                }
                else if(link.point > max_point) {
                    answer = link.index;
                    max_point = link.point;
                }
            }

            return answer;
        }

        class Link{
            String url;
            String[] ext_urls;
            double point, link_point;
            int index;

            public Link(int i, String url){
                this.index = i;
                this.url = url;
            }
            
            public void setExtUrls(ArrayList<String> urls){
                this.ext_urls = new String[urls.size()];
                for(int i = 0; i < urls.size(); i++){
                    ext_urls[i] = urls.get(i);
                }
            }

            public void setLinkPoint(){
                this.link_point = this.point / ext_urls.length;
            }
        }
}

 

 

더 많은 코드 보기(GitHub) : github.com/dwkim-97/CodingTest

 

 

반응형
저작자표시 (새창열림)

'Programmers' 카테고리의 다른 글

[프로그래머스] 스티커 모으기(2) / Java  (0) 2021.03.24
[프로그래머스] 카드 짝 맞추기 / Java  (2) 2021.03.24
[프로그래머스] 거스름돈 / Java  (0) 2021.03.22
[프로그래머스] 외벽 점검 / Java  (3) 2021.03.22
[프로그래머스] 길 찾기 게임 / Java  (0) 2021.03.22
'Programmers' 카테고리의 다른 글
  • [프로그래머스] 스티커 모으기(2) / Java
  • [프로그래머스] 카드 짝 맞추기 / Java
  • [프로그래머스] 거스름돈 / Java
  • [프로그래머스] 외벽 점검 / Java
개발하는 사막여우
개발하는 사막여우
개발개발 주저리주저리
    반응형
  • 개발하는 사막여우
    개발하는 사막여우
    개발하는 사막여우
  • 전체
    오늘
    어제
    • All (311)
      • Books (13)
        • 읽기 좋은 코드가 좋은 코드다 (13)
      • Study (6)
        • Blockchain (3)
        • Algorithm (3)
      • Baekjoon (36)
      • Programmers (166)
      • LeetCode (15)
      • Open Source (1)
        • Youtube Popout Player (1)
      • Language (32)
        • Python (9)
        • JS (8)
        • Java (5)
        • HTML (6)
        • CSS (4)
      • Library & Framework (15)
        • React.js (15)
      • IDE (2)
        • IntelliJ (2)
      • Airdrop (9)
      • Tistory (2)
      • etc.. (7)
        • Cozubi (6)
        • lol-chess (0)
  • 블로그 메뉴

    • Github
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    알고리즘문제풀이
    읽기 좋은 코드가 좋은 코드다
    카카오 코딩테스트
    파이썬
    카카오 공채
    programmers
    클린 코드 작성법
    백준
    Cozubi
    코인줍줍
    신규 코인 에어드랍
    2018 KAKAO BLIND RECRUITMENT
    프로그래머스 위클리 챌린지
    카카오 알고리즘 문제
    코주비
    Python
    Java
    클린 코드
    코딩테스트연습
    프로그래머스
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
개발하는 사막여우
[프로그래머스] 매칭 점수 / Java
상단으로

티스토리툴바