매칭 점수

Lee1231234·2024년 4월 29일

코딩테스트

목록 보기
88/95

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

해결과정

문제 이해

  • 필요한것
    파싱
    기본 점수
    기본점수 / 외부 링크 사이즈
    외부링크로 받는 외부 점수
    정렬
  1. 파싱
    먼저 문제를 보면 파싱이 필요하다. 여기서 그냥 split을 통해서 문자열 파싱을 할수도 있지만 정규식을 통하면 더 간편한 파싱이 가능하다.
    파싱을 통해서 얻을 수 있는것은 기본 점수와 자신의 외부점수 그리고 연결된 링크들이다.
    먼저 자기자신의 url을 찾아보면

    한 웹페이지의 url은 HTML의 태그 내에 태그의 값으로 주어진다.
    예를들어, 아래와 같은 meta tag가 있으면
    이 웹페이지의 url은 https://careers.kakao.com/index 이다.

<meta property="og:url" content="https://careers.kakao.com/index" />

따라서 저기서 바뀌는 부분은 content안에 있는 careers...index부분이므로 이 부분만 따오면 자기자신의 url를 가져올수있다.

코드(자기 자신의 url)

  Matcher m = Pattern.compile("(<meta property=\"og:url\" content=\"https://(\\S*)\")").matcher(pages[i]);
            while(m.find()){
                String name = m.group(2);
               page[i].url =name;
            }     

이때 정규식 메소드인 group을 사용하면 간편하게 url를 따올수 있다.

다음으로는 원하는 Word이다.
워드의 값은 문자열이 이어진곳에서 나오면 안되며 abc가 워드라면 abc@abc는 2개지만
abcabc는 원하는 워드가 아니다. 따라서 [^A-Za-z]의 정규식을 사용하고
또 우리가 필요한값은 word의 값만 가져오면 되기때문에 그 외의 값을 제거할 것이 필요하다. 이를 위해서 전방탐색 혹은 후방탐색을 통한 제거인 ?<=,이나 ?=를 사용하여 word의 값만 일치할때 값을 가져오면 된다.

  m = Pattern.compile("(?i)(?<=[^a-zA-Z])("+word+")([^a-zA-Z])").matcher(pages[i]);
            while(m.find()){
             
                page[i].basic +=1;
            }

마지막으로 외부 url인데 외부 url은 처음했던 자기자신의 url과 비슷하게 작성되지만 여러개의 url이 필요하므로 ArrayList<>를 통해 값을 list화 시켜 저장한다.

이를 통해서 자신의 외부점수와 기본 점수를 계산할수있다.
이제 마지막으로 외부 url에 걸려있는 다른 url에게 점수를 전파하기만 하면된다.

for(int i=0;i<page.length;i++){
            for(String s : page[i].outurl){
                 for(int j=0;j<page.length;j++){
                      
                     if(i == j) continue;
                    
                     if(s.equals(page[j].url)){
                        page[j].total += page[i].outurlvalue;                    
                     }
                
                 }
            }
           
        }

이후 마지막으로 정렬을 하던지 아니면 순회하면서 Max값을 찾아 인덱스 번호를 리턴하면 문제가 해결된다.

코드

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Solution {
    public int solution(String word, String[] pages) {
       
      
        info[] page =new info[pages.length];
       
        
        for(int i=0;i<pages.length;i++){
            page[i] = new info();
            ArrayList<String> url =new ArrayList<>();
            // 자기 url 찾기  <meta property="og:url" content="https://careers.kakao.com/index" />
            Matcher m = Pattern.compile("(<meta property=\"og:url\" content=\"https://(\\S*)\")").matcher(pages[i]);
            while(m.find()){
                String name = m.group(2);
               page[i].url =name;
            }                               
            // basic 점수 찾기             
            m = Pattern.compile("(?i)(?<=[^a-zA-Z])("+word+")([^a-zA-Z])").matcher(pages[i]);
            while(m.find()){
             
                page[i].basic +=1;
            }
          
            // 외부 url 찾기
            m = Pattern.compile("(<a href=\"https://(\\S*)\">)").matcher(pages[i]);
            while(m.find()){
                String name = m.group(2);                  
                url.add(name);
            }
            page[i].outurl = new ArrayList<>(url);
            page[i].outurlvalue = (double)page[i].basic/(double)page[i].outurl.size();
            page[i].total = (double)page[i].basic;
        }
        //외부 url의 대한 자신의 점수 찾기
        for(int i=0;i<page.length;i++){
            for(String s : page[i].outurl){
                 for(int j=0;j<page.length;j++){
                      
                     if(i == j) continue;
                    
                     if(s.equals(page[j].url)){
                        page[j].total += page[i].outurlvalue;                    
                     }
                
                 }
            }
           
        }
        double max =0;
        int answer = 0;
        for(int i=0;i<pages.length;i++){
          
            if(max<page[i].total){
                answer =i;
                max= page[i].total;
            }
            
        }

        return answer;
    }
    class info{
        String url;
        int basic;
        ArrayList<String> outurl;
        double outurlvalue;
        double total;
    }
}

클린 코드를 위한 내 생각
사실 outrulavlue는 필요없는 속성이다. outurl을 통해서 바로 계산이 가능하기때문.
또한 class를 사용했지만 모든값이 public이라 편하게 값을 가져왔지만 만약 실제 코드라면 getter setter를 통해서 가져오는것이 맞다.
한번에 모든 내용을 썼지만 메소드화 시켜 분리하는것이 맞다.
예를들어서 내 url찾기,기본점수,외부url 찾기등은 비슷한점(패턴을 사용함)이 있고 이를 통해서 코드가 중복되는 것이 보이므로 메소드화시켜서 중복되는것은 하나로 처리하는것이 좋다.

profile
not null

0개의 댓글