[JS] [1차] 뉴스 클러스터링

DARTZ·2023년 6월 5일
0

알고리즘

목록 보기
119/135

작성 코드

function solution(str1, str2) {
    const reg = /[a-z]/;
    const str1Lower = str1.toLowerCase();
    const str2Lower = str2.toLowerCase();
    
    const str1Ob = {};
    const str2Ob = {};
    
    for (let i = 1; i < str1Lower.length; i++) {
        if (reg.test(str1Lower[i-1]) && reg.test(str1Lower[i])) {
            str1Ob[str1Lower[i-1] + str1Lower[i]] ? str1Ob[str1Lower[i-1] + str1Lower[i]]++ : str1Ob[str1Lower[i-1] + str1Lower[i]] = 1;
        }
    };
    for (let i = 1; i < str2Lower.length; i++) {
        if (reg.test(str2Lower[i-1]) && reg.test(str2Lower[i])) {
            str2Ob[str2Lower[i-1] + str2Lower[i]] ? str2Ob[str2Lower[i-1] + str2Lower[i]]++ : str2Ob[str2Lower[i-1] + str2Lower[i]] = 1;
        }
    };
    
    let intersection = 0;
    
    Object.keys(str2Ob).forEach((v) => {
        if (str1Ob[v]) {
            intersection += Math.min(str1Ob[v], str2Ob[v]);
            str1Ob[v] = Math.max(str1Ob[v], str2Ob[v]);
        } else {
            str1Ob[v] = str2Ob[v];
        };
    });
    
    let union = 0;
    Object.values(str1Ob).forEach((v) => {
        union += v; 
    });
    
    return union === 0 && intersection === 0 ? 65536 : Math.floor(intersection / union * 65536);
}

처음에는 중복을 허용하는 집합인지 모르고 풀다가 오답이 나왔습니다. 문제를 잘 읽어보니 중복을 허용하는 집합이라 코드를 고쳤습니다. 문제는 처음부터 끝까지 차근차근 꼼꼼하게 읽어봐야겠습니다.

문제 알고리즘

  • 알파벳으로 이루어진 2개의 문자만 허용하므로 정규식을 통해서 알파벳을 판별해줍니다.
  • 소문자 대문자를 구별하지 않으므로 소문자로 통일해줍니다.
  • index는 1부터 시작합니다. 전 값이 알파벳이고 현재 값이 알파벳이면 두개를 더한 값이 객체에 존재하는지 판단하면서 객체를 채웁니다. (2번)
  • 이후에 한 객체를 key값으로 반복하면서 다른 객체에 있을 경우 Math.min을 통해 교집합 갯수를 구합니다. 그리고 합집합을 위해 Math.max를 통해 값을 변경해줍니다. 다른 객체에 없을 경우 합집합을 만들어주기 위해 다른 객체에 값을 그대로 저장해줍니다.
  • 합집합이 된 객체의 값을 반복하면서 더해주면 union 값이 나오게 됩니다.
  • 공집합은 1이므로 공집합일 경우 문제에 조건인 65536을 곱한 값을 반환해주면 됩니다.

다른 사람 코드

function solution (str1, str2) {

  function explode(text) {
    const result = [];
    for (let i = 0; i < text.length - 1; i++) {
      const node = text.substr(i, 2);
      if (node.match(/[A-Za-z]{2}/)) {
        result.push(node.toLowerCase());
      }
    }
    return result;
  }

  const arr1 = explode(str1);
  const arr2 = explode(str2);
  const set = new Set([...arr1, ...arr2]);
  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);
  })
  return union === 0 ? 65536 : Math.floor(intersection / union * 65536);
}

위에서 풀었던 코드는 통과가 되지만 효율적인 코드 작성을 위해 다른 사람의 코드는 어떤식으로 구현했는지 보고 싶어 가져왔습니다.

  function explode(text) {
    const result = [];
    for (let i = 0; i < text.length - 1; i++) {
      const node = text.substr(i, 2);
      if (node.match(/[A-Za-z]{2}/)) {
        result.push(node.toLowerCase());
      }
    }
    return result;
  }

str1과 str2의 반복되는 작업이므로 내부 함수를 작성하여 코드의 수를 줄였습니다.
index는 0부터 substr을 통해서 2개씩 문자열을 잘라주고 정규식 /[A-Za-z]{2}/로 2개의 알파벳으로 이루어져 있는지 확인하고 소문자로 변환하여 push해주었습니다.

저는 정규식 test를 사용했고 위에 코드는 match를 사용했는데 둘의 차이는 아래와 같습니다.

test() - 매칭되는것이 있다면 true 없다면 false 리턴
match() - 매칭되는것이 있다면 매칭된 문자열 출력

사용하고 싶은 것을 사용해도 무방합니다.

  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);
  })

그리고 여기서는 set의 값을 반복하면서 각 원소의 갯수를 구해서 union과 intersection으로 더해주었습니다.

union === 0 ? 65536 : Math.floor(intersection / union * 65536);

마지막은 어차피 합집합이 0개면 교집합도 0개이니 union만 0인지 확인해주고 반환했습니다.

배운 것들

  • 문자열 substr 사용.
  • 정규식에서 글자 갯수는 {2}로 표현 가능하다는 것.
  • 문제를 처음부터 끝까지 잘 읽어봐야 한다는 것.
profile
사람들이 비용을 지불하고 사용할 만큼 가치를 주는 서비스를 만들고 싶습니다.

0개의 댓글