Practice for coding test

프로그래머스 - Level 2. [1차] 뉴스 클러스터링 / JavaScript (js)

Gray Park 2023. 3. 2. 11:30
728x90
반응형

문제설명

문제분석

이 문제는 (1) 두 문자열을 입력받아 각 문자열에 대해 2글자씩 끊어서 집합을 만드는 문제(2) 두 집합의 교집합과 합집합의 길이를 구하고 자카드 유사도를 계산하는 문제로 구분할 수 있습니다. 각 문제별로 살펴보면 다음과 같습니다.

  • 두 문자열을 입력받아 각 문자열에 대해 2글자씩 끊어서 집합을 만드는 문제
    • 두 문자열이지만, 결국 하나의 함수를 작성해서 두 문자열에 대해 함수를 호출한다.
    • 반복문을 돌면서 i번째 요소 + (i+1)번째 요소가 각각 문자인 경우, toLowerCase를 적용해 결과에 저장한다
    • 반복문이 끝나면 결과를 리턴한다.
  • 두 집합의 교집합과 합집합의 길이를 구하고 자카드 유사도를 계산하는 문제
    • 두 집합(A, B)의 교집합을 구하기 위해서는 집합 A를 순회하며 집합 B에 존재하는 요소를 확인하면 된다.

문제를 단순화 했으니 이해하기 쉽게 코드를 짜보겠습니다.

 

반응형

이해하기 쉽게 코드작성하기

function solution(str1, str2) {
    const CONSTANT = 65536;
    const [setStr1, setStr2] = [genSet(str1), genSet(str2)];
    if(setStr1.length === 0 && setStr2.length === 0) return CONSTANT;
    const interLen = getIntersectionLength(setStr1, setStr2);
    const unionLength = setStr1.length + setStr2.length - interLen;
    return Math.floor((interLen / unionLength) * CONSTANT);
}

// 두 배열의 교집합의 길이를 리턴
function getIntersectionLength(arr1, arr2) {
    const result = [];
    let tmpArr2 = [...arr2];
    return arr1.map(x => {
        const idx = tmpArr2.indexOf(x);
        if(idx > -1) {
            tmpArr2 = tmpArr2.slice(0, idx).concat(tmpArr2.slice(idx + 1));
            return true;
        }
        return false;
    }).filter(x => x).length;
}

// 문자열을 2글자씩 끊어 배열로 만들어 리턴
function genSet(str) {
    str = str.toLowerCase();
    const result = [];
    
    for(let i = 0; i < str.length - 1; i++) {
        if(isAlphabet(str[i]) && isAlphabet(str[i + 1])) {
            result.push(str[i] + str[i + 1]);
        }
    }
    return result;
}

// 문자가 알파벳인지 검사
function isAlphabet(ch) {
    return 97 <= ch.charCodeAt() && ch.charCodeAt() <= 122;
}

 

 

합집합의 길이는 집합 A의 길이에 집합 B의 길이를 더하고, 마지막으로 두 집합의 교집합의 길이를 빼면 됩니다. 이 문제에서는 교집합의 길이만 구할 수 있으면 되기때문에 위 코드로도 충분히 깔끔하다고 생각하지만, Set을 사용해 교집합의 길이와 합집합의 길이를 구하는 부분을 조금 더 직관적으로 변경할 수 있습니다.

 

function solution(str1, str2) {
    const CONSTANT = 65536;
    const [setStr1, setStr2] = [genSet(str1), genSet(str2)];
    if(setStr1.length === 0 && setStr2.length === 0) return CONSTANT;
    
    const set = new Set([...setStr1, ...setStr2]);
    let interLen = 0, unionLen = 0;
    set.forEach(x => {
        const existsLen1 = setStr1.filter(y => x === y).length;
        const existsLen2 = setStr2.filter(y => x === y).length;
        interLen += Math.min(existsLen1, existsLen2);
        unionLen += Math.max(existsLen1, existsLen2);
    });
    
    return Math.floor((interLen / unionLen) * CONSTANT);
}

function genSet(str) {
    str = str.toLowerCase();
    const result = [];
    
    for(let i = 0; i < str.length - 1; i++) {
        if(isAlphabet(str[i]) && isAlphabet(str[i + 1])) {
            result.push(str[i] + str[i + 1]);
        }
    }
    return result;
}
    
function isAlphabet(ch) {
    return 97 <= ch.charCodeAt() && ch.charCodeAt() <= 122;
}
728x90
반응형