[JavaScript] 프로그래머스 LV2. [1차] 뉴스 클러스터링

정종훈·2022년 6월 8일

알고리즘 문제풀이

목록 보기
5/10

요약

걸린시간 :

대략 3일...

추가적으로 시간이 걸린 이유 :

  • 중복요소가 있을때 합집합과 교집합을 구현하는 부분
  • 정규식 패턴의 복습

첫 성공 코드

function solution(str1, str2) {
  // 문자만 쓰는 정규식 패턴
  let pattern = /[a-zA-Z]/;

  // str1과 str2의 문자열을 2개씩 끊는다. 그것을 각각 배열 변수 str1Subset, str2Subset 이라 한다.
  const strToSubsetTwoLetter = (str) => {
    str = str.toLowerCase();
    let result = [];
    for (let i = 0; i < str.length - 1; i++) {
      // 2개씩 끊는중 영문자로 된 글자 쌍만 result에 푸쉬한다.
      if (pattern.test(str[i]) && pattern.test(str[i + 1])) {
        result.push(str[i] + str[i + 1]);
      }
    }
    return result;
  };
  const str1Subset = strToSubsetTwoLetter(str1); // [ 'ba', 'aa', 'aa', 'aa' ]
  const str2Subset = strToSubsetTwoLetter(str2); // [ 'aa', 'aa' ]
  console.log("27번쨰", str1Subset, str2Subset);

  // str1Subset과 str2Subset의 교집합의 개수 intersection, 합집합의 개수 union을 구한다.
  let intersectionCopy = [...str2Subset];
  let duplicationLetter = "";
  const intersection = str1Subset.filter((el) => {
    if (intersectionCopy.includes(el)) {
      duplicationLetter = el;
      let idx = intersectionCopy.indexOf(el);
      intersectionCopy.splice(idx, 1);
      return true;      
    } else {
      return false;
    }
  })
  
  let union = [...str1Subset];
  let unionCopy = [...str1Subset];
  str2Subset.forEach((el) => {
    if (unionCopy.includes(el)) {
      duplicationLetter = el;
      let idx = unionCopy.indexOf(el);
      unionCopy.splice(idx, 1);
    } else {
      union.push(el);
    }
  });
  // console.log("43번쨰", intersection, union);

  // intersection / union * 65536 하고 소수점 아래를 버린 값을 리턴한다.
  if (intersection.length === 0 && union.length === 0) {
    return 65536
  }
  return Math.floor((intersection.length / union.length) * 65536);
}

console.log(solution("BAAAA", "AAA"));

느낀점

정규식 표현은 간단하지만 아주 유용하다. 허나 매번 볼때마다 까먹기 때문에 체화가 필요하다.

아마 union intersection을 만들때 그냥 단순히 하게 되면 중복 요소에 대해 문제가 생긴다.

예를 들어

str1 = ["BA", "AA", "AA", ""AA"]
str2 = ["AA", ""AA"]
answer: 32768

일때 그냥 교집합을 하게 되면 str1이 그대로 나오게 된다.
따라서 str2를 copy하여 겹칠떄마다 str2의 요소들을 없앰으로써 처리를 하였다.

코드 개선할 점

  • 정규식 처리 부분
  • 합집합 교집합 구하는 방식
  • 마지막 0 / 0 일때 리턴하는 방식

리팩토링 코드

function solution(str1, str2) {
  // 문자만 쓰는 정규식 패턴
  let pattern = /[a-z]{2}/;

  // str1과 str2의 문자열을 2개씩 끊는다. 그것을 각각 배열 변수 str1Subset, str2Subset 이라 한다.
  const strToSubsetTwoLetter = (str) => {
    str = str.toLowerCase();
    let result = [];
    for (let i = 0; i < str.length - 1; i++) {
      // 2개씩 끊는중 영문자로 된 글자 쌍만 result에 푸쉬한다.
      const tmp = str.substr(i, 2)
      if (pattern.test(tmp)) {
        result.push(tmp);
      }
    }
    return result;
  };
  const str1Subset = strToSubsetTwoLetter(str1); // [ 'ba', 'aa', 'aa', 'aa' ]
  const str2Subset = strToSubsetTwoLetter(str2); // [ 'aa', 'aa' ]
  // console.log("20번쨰", str1Subset, str2Subset);

  // str1Subset과 str2Subset의 교집합의 개수 intersection, 합집합의 개수 union을 구한다. 아이디어 신기
  const arr1 = strToSubsetTwoLetter(str1);
  const arr2 = strToSubsetTwoLetter(str2);
  const set = new Set([...arr1, ...arr2]);
  console.log("26번째", arr1, arr2, set)
  let union = 0;
  let intersection = 0;

  set.forEach(item => {
    const has1 = arr1.filter(x => x === item).length;
    const has2 = arr2.filter(x => x === item).length;
    union += Math.max(has1, has2);
    intersection += Math.min(has1, has2);
  })

  // intersection / union * 65536 하고 소수점 아래를 버린 값을 리턴한다.
  return union === 0 ? 65536 : Math.floor(intersection / union * 65536);
}

console.log(solution("handshake", "shake hands"));
profile
괴발개발자에서 개발자로 향해보자

0개의 댓글