[프로그래머스] 뉴스 클러스터링
프로그래머스
2018 KAKAO BLIND RECRUITMENT
- [1차] 뉴스 클러스터링
코딩테스트 연습 - [1차] 뉴스 클러스터링
뉴스 클러스터링 여러 언론사에서 쏟아지는 뉴스, 특히 속보성 뉴스를 보면 비슷비슷한 제목의 기사가 많아 정작 필요한 기사를 찾기가 어렵다. Daum 뉴스의 개발 업무를 맡게 된 신입사원 튜브
programmers.co.kr
시작하기 전 접근 방법
어떻게 접근해서 진행해야 할지 먼저 생각을 하였다.
1. s1과 s2는 영어 대/소문자와 특수문자로 구성되어 있는 문자열이다.
1-1 먼저 문자열을 소문자로 통일한다.(문자를 비교할 때 더 편리하게 하기 위해서)
2. 문제에 입력형식에서 영문자로 된 글자 쌍만 유효하고 기타 문자는 버린다고 나와있기 때문에 문자열 버리기
3. 영문자로된 2 글자씩 끊어서 확인하기
4. 교집합과 합집합으로 분류해서 저장하기
5. 문제에서 구해야하는 자카드 유사도 구하기

생각했던 1번과 교집합과 합집합을 저장할 list와 2개씩 끊어서 문자열을 만든 문자를 저장할 list2개를 만든다.
String str1 = s1.toLowerCase();
String str2 = s2.toLowerCase();
ArrayList<String> str1List = new ArrayList<>(); // str1문장 2개씩 잘라둔 문장 저장
ArrayList<String> str2List = new ArrayList<>(); // str2문장 2개씩 잘라둔 문장 저장
ArrayList<String> union = new ArrayList<>(); // 합집합
ArrayList<String> intersection = new ArrayList<>(); // 교집합
매개값으로 주어진 문자열을 2개씩 잘라서 확인하며 영문자가 아닌 다른 문자가 있는지 확인하는 과정
반복문을 이용해서 문자열 인덱스를 가져오고 char형으로 되어 있는 문자를 String.valueOf를 이용해서 String형으로 변환
for(int i=0; i<str1.length()-1; i++){
char ch1 = str1.charAt(i);
char ch2 = str1.charAt(i+1);
if((ch1 >= 'a' && ch1 <= 'z') && (ch2 >= 'a' && ch2 <= 'z')) {
str1List.add(String.valueOf(ch1) + String.valueOf(ch2));
}
}
for (int i = 0; i < str2.length()-1; i++) {
char ch1 = str2.charAt(i);
char ch2 = str2.charAt(i+1);
if((ch1 >= 'a' && ch1 <= 'z') && (ch2 >= 'a' && ch2 <= 'z')) {
str2List.add(String.valueOf(ch1) + String.valueOf(ch2));
}
}
3,4번 과정을 생각하기 위해서 str1List에 저장되어 있는 문자를 반복문을 통해서 str2List 값과 비교를 한다.
str1List에 있는 문자가 str2List에 있다면 str2List에 해당 문자를 삭제하고 교집합을 구하기 위한 List인 intersection리스트에 저장하고 교집합 List에 저장을 못해도 List에 있는 모든 문자는 합집합에 저장한다.
for(String s : str1List){
if(str2List.remove(s)){
intersection.add(s);
}
union.add(s);
}
union.addAll(str2List);
5번 자가 유사도 구하기!
double result = (double)intersection.size() / (double)union.size();
result = result * 65536;
if(union.size()==0){
return 65536;
}
answer = (int)result;
return answer;
}
여기서 문제가 많았다.
2가지 문제가 발생을 했다...
1번째는 문자를 2개씩 나누는 과정에서 List에 값이 하나도 없는 경우에는 어떻게 처리해야하는지 문제점
2번째는 출력값에 타입에 대한 고민이였다.
1번째 경우 4번째 테스트 매개 값인 경우 문제가 발생했다. 문자를 2개씩 나눠 List에 저장하는 과정에서 특수문자와 숫자가 있다면 문자열을 자르는 코드에서 if문에서 걸러진다. 그래서 List에는 저장이 되지 않는다. 이렇게 되면 자가 유사도 구하는 코드에서 result값이 0*65536을 하면 0이 나오고 합집합인 union리스트 크기가 0이기 때문이다. 그래서 union리스트 크기가 0일 때는 어떻게 처리해줘야 하는지 코드가 필요하였다. 이 문제를 처음에 생각하지 않고 코드를 작성하여 테스트 4 결과가 실패가 나왔다.
두 번째 문제점은 출력 형식 문제였다. 문제에 내용인 출력 형식에서 유사도 값은 0과 1 실수이다. 이 부분을 생각하지 않고 바로 결괏값을 int형으로 깊게 생각하지 않고 타입을 선택했다. 조금 더 생각해 봤으면 double result = (double)intersection.size() / (double)union.size(); 이 부분은 1보다 클 수가 없었다. 교집합이 합집합과 같을 수 는 있지만 합집합도가 클수가 없었다...
그래서 실수 타입인 double로 수정하고 List크기를 double타입으로 캐스팅을 하여 구하였다.
그리고 이 계산한 실수 타입을 65536을 곱하고 소수점 아래를 버리고 정수부분만 출력하기 위해서는 double를 다시 int형으로 바꾸면 소수점은 버려지기 때문에 마지막 answer = (int)result; 부분을 캐스팅해서 결괏값을 구하였다.
타입 선정에 대해 깊게 생각하지 못하고 문제를 조금 더 고민하지 못해서 발생한 문제점이었다.
최종 코드
List를 사용하기 위해서(import java.util.ArrayList)가 필요
import java.util.ArrayList;
class Solution {
public int solution(String s1, String s2) {
int answer = 0;
String str1 = s1.toLowerCase();
String str2 = s2.toLowerCase();
ArrayList<String> str1List = new ArrayList<>();
ArrayList<String> str2List = new ArrayList<>();
ArrayList<String> union = new ArrayList<>(); //합집합
ArrayList<String> intersection = new ArrayList<>(); //교집합
for(int i=0; i<str1.length()-1; i++){
char ch1 = str1.charAt(i);
char ch2 = str1.charAt(i+1);
if((ch1 >= 'a' && ch1 <= 'z') && (ch2 >= 'a' && ch2 <= 'z')) {
str1List.add(String.valueOf(ch1) + String.valueOf(ch2));
}
}
for (int i = 0; i < str2.length()-1; i++) {
char ch1 = str2.charAt(i);
char ch2 = str2.charAt(i+1);
if((ch1 >= 'a' && ch1 <= 'z') && (ch2 >= 'a' && ch2 <= 'z')) {
str2List.add(String.valueOf(ch1) + String.valueOf(ch2));
}
}
for(String s : str1List){
if(str2List.remove(s)){
intersection.add(s);
}
union.add(s);
}
union.addAll(str2List);
double result = (double)intersection.size() / (double)union.size();
result = result * 65536;
if(union.size()==0){
return 65536;
}
answer = (int)result;
return answer;
}
}