Skip to content

Commit 46ac7bf

Browse files
committed
[level 2] Title: [1차] 뉴스 클러스터링, Time: 1.10 ms, Memory: 69.7 MB -BaekjoonHub
1 parent dda9a68 commit 46ac7bf

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# [level 2] [1차] 뉴스 클러스터링 - 17677
2+
3+
[문제 링크](https://school.programmers.co.kr/learn/courses/30/lessons/17677?language=java)
4+
5+
### 성능 요약
6+
7+
메모리: 69.7 MB, 시간: 1.10 ms
8+
9+
### 구분
10+
11+
코딩테스트 연습 > 2018 KAKAO BLIND RECRUITMENT
12+
13+
### 채점결과
14+
15+
정확성: 100.0<br/>합계: 100.0 / 100.0
16+
17+
### 제출 일자
18+
19+
2025년 06월 27일 17:08:39
20+
21+
### 문제 설명
22+
23+
<h2>뉴스 클러스터링</h2>
24+
25+
<p>여러 언론사에서 쏟아지는 뉴스, 특히 속보성 뉴스를 보면 비슷비슷한 제목의 기사가 많아 정작 필요한 기사를 찾기가 어렵다. Daum 뉴스의 개발 업무를 맡게 된 신입사원 튜브는 사용자들이 편리하게 다양한 뉴스를 찾아볼 수 있도록 문제점을 개선하는 업무를 맡게 되었다.</p>
26+
27+
<p>개발의 방향을 잡기 위해 튜브는 우선 최근 화제가 되고 있는 "카카오 신입 개발자 공채" 관련 기사를 검색해보았다.</p>
28+
29+
<ul>
30+
<li>카카오 첫 공채..'블라인드' 방식 채용</li>
31+
<li>카카오, 합병 후 첫 공채.. 블라인드 전형으로 개발자 채용</li>
32+
<li>카카오, 블라인드 전형으로 신입 개발자 공채</li>
33+
<li>카카오 공채, 신입 개발자 코딩 능력만 본다</li>
34+
<li> 카카오, 신입 공채.. "코딩 실력만 본다"</li>
35+
<li>카카오 "코딩 능력만으로 2018 신입 개발자 뽑는다"</li>
36+
</ul>
37+
38+
<p>기사의 제목을 기준으로 "블라인드 전형"에 주목하는 기사와 "코딩 테스트"에 주목하는 기사로 나뉘는 걸 발견했다. 튜브는 이들을 각각 묶어서 보여주면 카카오 공채 관련 기사를 찾아보는 사용자에게 유용할 듯싶었다.</p>
39+
40+
<p>유사한 기사를 묶는 기준을 정하기 위해서 논문과 자료를 조사하던 튜브는 "자카드 유사도"라는 방법을 찾아냈다.</p>
41+
42+
<p>자카드 유사도는 집합 간의 유사도를 검사하는 여러 방법 중의 하나로 알려져 있다. 두 집합 <code>A</code>, <code>B</code> 사이의 자카드 유사도 <code>J(A, B)</code>는 두 집합의 교집합 크기를 두 집합의 합집합 크기로 나눈 값으로 정의된다.</p>
43+
44+
<p>예를 들어 집합 <code>A</code> = {1, 2, 3}, 집합 <code>B</code> = {2, 3, 4}라고 할 때, 교집합 <code>A ∩ B</code> = {2, 3}, 합집합 <code>A ∪ B</code> = {1, 2, 3, 4}이 되므로, 집합 <code>A</code>, <code>B</code> 사이의 자카드 유사도 <code>J(A, B)</code> = 2/4 = 0.5가 된다. 집합 A와 집합 B가 모두 공집합일 경우에는 나눗셈이 정의되지 않으니 따로 <code>J(A, B)</code> = 1로 정의한다.</p>
45+
46+
<p>자카드 유사도는 원소의 중복을 허용하는 다중집합에 대해서 확장할 수 있다. 다중집합 <code>A</code>는 원소 "1"을 3개 가지고 있고, 다중집합 <code>B</code>는 원소 "1"을 5개 가지고 있다고 하자. 이 다중집합의 교집합 <code>A ∩ B</code>는 원소 "1"을 min(3, 5)인 3개, 합집합 <code>A ∪ B</code>는 원소 "1"을 max(3, 5)인 5개 가지게 된다. 다중집합 <code>A</code> = {1, 1, 2, 2, 3}, 다중집합 <code>B</code> = {1, 2, 2, 4, 5}라고 하면, 교집합 <code>A ∩ B</code> = {1, 2, 2}, 합집합 <code>A ∪ B</code> = {1, 1, 2, 2, 3, 4, 5}가 되므로, 자카드 유사도 <code>J(A, B)</code> = 3/7, 약 0.42가 된다.</p>
47+
48+
<p>이를 이용하여 문자열 사이의 유사도를 계산하는데 이용할 수 있다. 문자열 "FRANCE"와 "FRENCH"가 주어졌을 때, 이를 두 글자씩 끊어서 다중집합을 만들 수 있다. 각각 {FR, RA, AN, NC, CE}, {FR, RE, EN, NC, CH}가 되며, 교집합은 {FR, NC}, 합집합은 {FR, RA, AN, NC, CE, RE, EN, CH}가 되므로, 두 문자열 사이의 자카드 유사도 <code>J("FRANCE", "FRENCH")</code> = 2/8 = 0.25가 된다.</p>
49+
50+
<h3>입력 형식</h3>
51+
52+
<ul>
53+
<li>입력으로는 <code>str1</code>과 <code>str2</code>의 두 문자열이 들어온다. 각 문자열의 길이는 2 이상, 1,000 이하이다.</li>
54+
<li>입력으로 들어온 문자열은 두 글자씩 끊어서 다중집합의 원소로 만든다. 이때 영문자로 된 글자 쌍만 유효하고, 기타 공백이나 숫자, 특수 문자가 들어있는 경우는 그 글자 쌍을 버린다. 예를 들어 "ab+"가 입력으로 들어오면, "ab"만 다중집합의 원소로 삼고, "b+"는 버린다.</li>
55+
<li>다중집합 원소 사이를 비교할 때, 대문자와 소문자의 차이는 무시한다. "AB"와 "Ab", "ab"는 같은 원소로 취급한다.</li>
56+
</ul>
57+
58+
<h3>출력 형식</h3>
59+
60+
<p>입력으로 들어온 두 문자열의 자카드 유사도를 출력한다. 유사도 값은 0에서 1 사이의 실수이므로, 이를 다루기 쉽도록 65536을 곱한 후에 소수점 아래를 버리고 정수부만 출력한다.</p>
61+
62+
<h3>예제 입출력</h3>
63+
<table class="table">
64+
<thead><tr>
65+
<th>str1</th>
66+
<th>str2</th>
67+
<th>answer</th>
68+
</tr>
69+
</thead>
70+
<tbody><tr>
71+
<td>FRANCE</td>
72+
<td>french</td>
73+
<td>16384</td>
74+
</tr>
75+
<tr>
76+
<td>handshake</td>
77+
<td>shake hands</td>
78+
<td>65536</td>
79+
</tr>
80+
<tr>
81+
<td>aa1+aa2</td>
82+
<td>AAAA12</td>
83+
<td>43690</td>
84+
</tr>
85+
<tr>
86+
<td>E=M*C^2</td>
87+
<td>e=m*c^2</td>
88+
<td>65536</td>
89+
</tr>
90+
</tbody>
91+
</table>
92+
<p><a href="http://tech.kakao.com/2017/09/27/kakao-blind-recruitment-round-1/" target="_blank" rel="noopener">해설 보러가기</a></p>
93+
94+
95+
> 출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import java.util.List;
2+
import java.util.ArrayList;
3+
import java.util.Map;
4+
import java.util.HashMap;
5+
import java.util.Set;
6+
import java.util.HashSet;
7+
8+
class Solution {
9+
public int solution(String str1, String str2) {
10+
11+
String lowerStr1 = str1.toLowerCase();
12+
String lowerStr2 = str2.toLowerCase();
13+
14+
Map<String, Integer> str1List = new HashMap<>();
15+
for(int i =0; i<lowerStr1.length()-1; i++) {
16+
String substringStr = lowerStr1.substring(i, i+2);
17+
if(substringStr.charAt(0) < 97 || substringStr.charAt(0) >122
18+
|| substringStr.charAt(1) < 97 || substringStr.charAt(1) > 122) {
19+
continue;
20+
}
21+
str1List.put(substringStr, str1List.getOrDefault(substringStr,0) +1);
22+
}
23+
24+
Map<String, Integer> str2List = new HashMap<>();
25+
for(int i =0; i<lowerStr2.length()-1; i++) {
26+
String substringStr = lowerStr2.substring(i, i+2);
27+
if(substringStr.charAt(0) < 97 || substringStr.charAt(0) >122
28+
|| substringStr.charAt(1) < 97 || substringStr.charAt(1) > 122) {
29+
continue;
30+
}
31+
str2List.put(substringStr, str2List.getOrDefault(substringStr,0) +1);
32+
}
33+
34+
if(str1List.size() == 0 && str2List.size() ==0) {
35+
return 65536;
36+
}
37+
38+
int union = 0;
39+
int intersection = 0;
40+
Set<String> visited = new HashSet<>();
41+
for (String key : str1List.keySet()) {
42+
int str1Count = str1List.get(key);
43+
int str2Count = 0;
44+
if(str2List.containsKey(key)) {
45+
str2Count = str2List.get(key);
46+
}
47+
48+
int max = Math.max(str1Count, str2Count);
49+
int min = Math.min(str1Count, str2Count);
50+
union += max;
51+
intersection += min;
52+
visited.add(key);
53+
}
54+
55+
for(String key : str2List.keySet()) {
56+
if(!visited.contains(key)) {
57+
union += str2List.get(key);
58+
}
59+
}
60+
61+
double sum = (double)intersection/(double)union;
62+
63+
int answer = (int)(sum * 65536.0);
64+
65+
return answer;
66+
}
67+
//97 122
68+
69+
}

0 commit comments

Comments
 (0)