공돌이의 지식 저장소

[TIL]내배캠 7일차 (프로그래머스 풀다가 문제 생긴 경험) 본문

내배캠/TIL(Today I Learned)

[TIL]내배캠 7일차 (프로그래머스 풀다가 문제 생긴 경험)

도오라에몽 2023. 5. 23. 18:58

오늘은 그냥 자바스크립트 내용 중에서 모르거나 헷갈리는 부분 또는 진짜 독특한 부분만 골라서 듣고 프로그래머스에서 '문자열 내 마음대로 정렬하기'라는 문제를 풀어봤다. 자바스크립트로는 객체들이 제공해주는 함수를 사용하여 쉽게 풀 수 있을 것 같지만 본인은 제공 함수를 사용하지 않고 스스로 생각하며 푸는 길을 선택하였다. 자고로 프로그래머란 기존에 있는 도구를 활용하는 것도 중요하지만 본인이 직접 한 단계씩 생각하며 로직을 짜는 것도 매우 중요한 덕목이 아닐까 싶다. 그리고 그게 코딩테스트의 본질이 아닌가 싶다.

문제점

먼저 문제가 되는 코드를 적어놓겠다.

function solution(strings, n) {
    var answer = [];

    for (let i = 0; i < strings.length - 1; i++) {
        for (let j = i + 1; j < strings.length - 1; j++) {
            if (!checkNthOrder(strings[i][n], strings[j][n], "asc")) {
                let temp;
                temp = strings[i];
                strings[i] = strings[j];
                strings[j] = temp;
            }
        }
        console.log(strings);
    }

    return answer;
}

function checkNthOrder(str1, str2, n, orderOption = "asc") {
    if (orderOption === "desc") {
        if (str1.charCodeAt(n) === str2.charCodeAt(n)) {
            checkNthOrder(str1, str2, n + 1, orderOption); // 재귀 호출을 할 때마다 비교하는 문자열의 인덱스가 1씩 증가
        }
        else if (str1.charCodeAt(n) > str2.charCodeAt(n)) {
            return true;
        }
        else {
            return false;
        }
    }
    else {
        if (orderOption !== "asc") {
                orderOption = "asc";
                console.log(`정렬 기준이 ${orderOption}으로 되어있어 asc를 기준으로 정렬 진행하였습니다.`);
        }

        if (str1.charCodeAt(n) === str2.charCodeAt(n)) {
            checkNthOrder(str1, str2, n + 1, orderOption);
        }
        else if (str1.charCodeAt(n) < str2.charCodeAt(n)) {
            return true;
        }
        else {
            return false;
        }
    }
}

문제의 내용은 checkNthOrde 함수에서 RangeError: Maximum call stack size exceeded 에러를 내보내는 것이다.
아무래도 스택오버플로우의 여지가 있나보다.

시도한 것

우선 코드에서 재귀호출이 되는 부분을 보면 return 되는 부분이 없다. 그래서 후에 조건 충족 시 루프를 빠져나갈 수 있도록 코드를 고쳤는데 그것도 여전히 스택오버플로우 에러를 보여준다.

그래서 과감히 재귀호출 방식을 포기하며 문제를 다시 봤다.

그리고 또다시 생긴 문제점...

코드를 짜기위해 문제를 다시 봤는데 문제 조건을 잘못 이해했다...(ㅠㅠ) 그런데 약간 억울한게 문제도 조건을 약간 이해하기 힘들게 적어놨다.
내가 이해했던 조건은 n번째 인덱스의 알파벳이 같으면 n + 1번째 이후에 오는 문자열들에 대하여 오름차순 정렬 하는 것인 줄 알았는데 그냥 단어 자체로 오름차순 정렬 하는 것이었다.

문제 해결에 사용한 코드

function solution(strings, n) {
    let answer = strings;

    for (let i = 0; i < strings.length - 1; i++) {
        for (let j = i + 1; j < strings.length; j++) {
            if (!checkNthOrder(answer[i], answer[j], n, "asc")) {
                let temp;
                temp = answer[i];
                answer[i] = answer[j];
                answer[j] = temp;
            }
        }
    }

    return answer;
}

// n번째 알파벳을 비교하고 오름차순이면 참을, 그렇지 않으면 거짓을 반환한다.
function checkNthOrder(source, destination, n, orderOption = 'asc') {
    if (source.charCodeAt(n) < destination.charCodeAt(n)) {
        return true;
    }
    else if (source.charCodeAt(n) > destination.charCodeAt(n)) {
        return false;
    }
    else {
        return isOrdered(source, destination, orderOption);
    }
}

// source는 현재 위치해있는 단어이고 destination은 다음에 위치할 단어이다. (curWord, nextWord라 했으면 좋았을려나?)
// 해당 함수는 현재 단어와 다음에 오는 단어를 비교하여 오름차순 정렬인지 내림차순 정렬인지 비교한다
// 만약 옵션으로 asc(오름차순)를 줬고 source, destination 순으로 오름차순이면 true를, 그렇지 않으면 false를 반환한다.
function isOrdered(source, destination, orderOption = 'asc') {
    let shorter_len;
    (source.length < destination.length) ? (shorter_len = source.length) : (shorter_len = destination.length);

    if (orderOption === 'desc') {
        for (let i = 0; i < shorter_len; i++) {
            if (source.charCodeAt(i) > destination.charCodeAt(i)) {
                return true;
            }
            else if (source.charCodeAt(i) < destination.charCodeAt(i)) {
                return false;
            }
            else {
                continue;
            }
        }
    // 이 부분에서는 서로 단어의 길이가 다른데 긴 단어의 일부가 짧은 단어랑 완전히 일치하는 경우도 생각하여 만들었다.
    // 여기는 내림차순 기준이니 단어 순서가 (긴 단어, 짧은 단어)가 오면 참을 반환한다.
        if (source.length > destination.length)
            return true;
        else
            return false;
    }
    else {
        if (orderOption !== "asc") {
            orderOption = "asc";
            console.log(
                `정렬 기준이 ${orderOption}으로 되어있어 asc를 기준으로 정렬 진행하였습니다.`
            );
        }

        for (let i = 0; i < shorter_len; i++) {
            if (source.charCodeAt(i) < destination.charCodeAt(i)) {
                return true;
            }
            else if (source.charCodeAt(i) > destination.charCodeAt(i)) {
                return false;
            }
            else {
                continue;
            }
        }

        if (source.length < destination.length)
            return true;
        else
            return false;
    }
}

문제를 풀고나니 다른 사람들은 기본적으로 제공하는 함수들을 많이 이용하는 것 같았다. 하지만 본인은 그냥 기능 구현을 하나하나 해보았다.

오늘의 교훈

코딩테스트 문제 풀 때는 문제를 잘 읽자 ^^

추가사항

오늘 한 내용을 튜터님께 검토받았고 어떤 부분을 고치는게 좋은지 추가적으로 뭘 공부하는게 좋을지도 피드백을 받았다.
피드백으로 받은 것은 자바스크립트에서 제공하는 함수를 적절하게 사용하는 것, 코드를 짤 때 시간복잡도를 고려할 것, 만약에 된다면 리팩토링도 한 번 학습해볼 것 이 세 가지 정도 되겠다.

Comments