[프로그래머스][JS]뉴스 클러스터링
문제
문제: https://programmers.co.kr/learn/courses/30/lessons/17677#
주어진 문자열을 조건에 맞게 배열로 만든다.
두 배열의 교집합/합집합 * 65536을 구하는 문제
해결방법
- 문자열을 주어진 조건에 맞게 만든다.
- 각 배열의 합집합의 수, 교집합의 수를 구해서 나눠준다.
문자열을 조건에 맞는 배열로 바꾸기
영문외에 공백, 숫자, 특수문자는 들어가면 되지 않기 때문에 아스키코드를 이용해서 판별했다.
function checkString(char) {
const charKey = char.toLowerCase().charCodeAt();
return charKey >= 97 && charKey <= 122;
}
위의 함수를 이용해 소문자로 바꿔서 영문이 확인되면 배열에 추가해주었다.
for문을 돌면서 각 char을 검사해주는데 char과 그 다음에오는 char을 검사해줘야 되기 때문에 str1[i + 1] && checkString(str1[i]) && checkString(str1[i + 1])
이라는 조건이 true
가 되면 배열에 넣어줬다. (i는 for문에서의 index이다.)
합집합 교집합 수 구하기
일단 수 만 구하면 된다.
합집합의 수 = 각 배열의 모든 요소들 합 - 교집합의 수
이기 때문에 교집합만 구하면 되는 문제이다.
교집합 구하기
- 주어진 문자열을 배열로만든
strFirstArr
,strSecondArr
을 이용해서 각각 객체로 만들어 주었다.
(firstObj
,secondObj
)
key값은 요소이고 value값은 key값의 개수이다.
ex) ['aa','aa','bb'] => {'aa':2, 'bb':1}
- 위 2개 중 하나의 객체를 선택해 순회하면서 같은 키값이 다른 객체에도 있다면 둘 중 작은 값만큼 교집합의 수 (
interactionSize
)에 더해주는 것으로 했다.
for (let key in firstObj) {
if (secondObj[key]) {
interactionSize += Math.min(firstObj[key], secondObj[key]);
}
}
code
function solution(str1, str2) {
let strFirstArr = [];
let strSecondArr = [];
for (let i = 0; i < str1.length; i++) {
if (str1[i + 1] && checkString(str1[i]) && checkString(str1[i + 1])) {
//대소문자가 같기 때문에 모두 소문자로 넣어준다.
strFirstArr.push(str1[i].toLowerCase() + str1[i + 1].toLowerCase());
}
}
for (let i = 0; i < str2.length; i++) {
if (str2[i + 1] && checkString(str2[i]) && checkString(str2[i + 1])) {
//대소문자가 같기 때문에 모두 소문자로 넣어준다.
strSecondArr.push(str2[i].toLowerCase() + str2[i + 1].toLowerCase());
}
}
let interactionSize = 0;
let unionSize = 0;
let firstObj = {};
let secondObj = {};
//교집합 구하기 위해 객체로 만들기
strFirstArr.forEach((v) => {
if (firstObj[v]) firstObj[v]++;
else firstObj[v] = 1;
});
strSecondArr.forEach((v) => {
if (secondObj[v]) secondObj[v]++;
else secondObj[v] = 1;
});
// 중복되는걸 교집합으로 더해준다.
for (let key in firstObj) {
if (secondObj[key]) {
interactionSize += Math.min(firstObj[key], secondObj[key]);
}
}
//교집합을 이용해 합집합을 구해준다.
unionSize = strFirstArr.length + strSecondArr.length - interactionSize;
if (!strFirstArr.length && !strSecondArr.length) return 1 * 65536;
else return Math.floor((interactionSize / unionSize) * 65536);
}
function checkString(char) {
const charKey = char.toLowerCase().charCodeAt();
return charKey >= 97 && charKey <= 122;
}
마무리
교집합을 구하는데 Map,Set을 이용해 보고 싶었지만 결국 편한 object로 구하게 됐다.
다른 사람이 푼 답안을 보니 Set을 사용하고, 카카오문제에서 제시했듯이 각요소가 있으면 min-교집합, max-합집합 으로 구한것을 보았다.
한번에 이해하기도 쉽고 카카오에서 제시한것을 이용해서 해결한것이 더 깔끔해보였다.
//set = strFirstArr, strSecondArr을 set으로 만든것
set.forEach(item => {
const has1 = arr1.filter(x => x === item).length;
const has2 = arr2.filter(x => x === item).length;
unionSize += Math.max(has1, has2);
intersectionSize += Math.min(has1, has2);
})
위의 코드처럼하면 보기에도 훨씬 깔끔하고 좋은 코드인것같다.
문제를 그냥 해결하는 것보다 효율적으로 해결하려는 능력을 연습해야 될것같다.
Author And Source
이 문제에 관하여([프로그래머스][JS]뉴스 클러스터링), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@proshy/프로그래머스JS뉴스-클러스터링저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)