1주차 도전 문제_01

윤수빈·2024년 8월 20일
0

1회차


1. 두 수의 최대 공약수

문제 설명

: 두 자연수 a와 b가 주어질 때, 이 둘의 최대공약수를 구하는 함수를 작성하세요.

문제 풀이

최대 공약수는 서로 나누어떨어지는 수를 구하고, 나누어 떨어지지 않을때까지 반복하면 된다.

하지만 반복을 언제까지 하느냐? 이 부분을 처리하는 것이 관건이었다.

약수를 구할 때, 자연수 x가 자연수 n에 의해 나누어 떨어진다고 가정하면 나눈 n 값과 나누어진 x의 값이 약수가 된다.
이렇게 나눈 값과 나누어진 값이 페어로 약수가 되는 점을 고려하면 나눈 값은 자연수 x의 제곱근보다 작을 수 밖에 없다는 것이 특징이 된다.

이 점을 고려해서 반복문을 자연수 x가 주어질 때 x의 제곱근만큼만 반복하도록 설정하였다.

전체 코드

function getCommonDivisor(a, b) {
    
    let min = Math.min(a, b);
    let max = Math.max(a, b);
    let res = 1;
    let i;

    for(let i=2; i<=Math.sqrt(max); i++) {
        while(max%i === 0 && min%i === 0) {
            res *= i;
            max /= i;
            min /= i;
        }
    }

    return res;
}

2. 짝수와 홀수

문제 설명

주어진 배열에서 짝수와 홀수의 개수를 각각 세는 함수를 작성하세요. 함수는 [짝수 개수, 홀수 개수]의 배열을 반환해야 합니다.

문제 풀이

주어진 배열을 반복하여 2로 나누어 떨어지는지 확인하고 짝수와 홀수 개수를 카운트했다.

전체 코드

function countEvenAndOdd(arr) {
    const answer = [0, 0];
    for(let i=0; i<arr.length; i++) {
        // 짝수
        if(arr[i] % 2===0) {
            answer[0]++;
        }
        else if(arr[i] %2 !== 0) {
            answer[1]++;
        }
    }
    return answer;
}

3. 문자열 역순 및 한칸 이동

문제 설명

문자열이 주어지면 해당 문자열을 역순으로 배치한 후, 알파벳을 하나씩 오른쪽으로 이동시킨 결과를 출력하세요. 예를 들어, a는 b, z는 a로 변환됩니다.

문제 풀이

역순으로 배치는 reverse()를 주었고, str이 문자열이기 때문에 reverse 메서드를 사용하기 위해 split 메서드로 배열로 바꾸어 주었다.
하나씩 오른쪽으로 이동 시키는 것은 각 문자를 ASCII 코드 10진수로 변환하여 증감해주는 방식으로 구현했다.

전체 코드

function reverseAndShift(str) {
    let tempStr = str.split('').reverse();
    console.log(tempStr);
    for(let i=0; i<tempStr.length; i++) {
        let transformChar = tempStr[i].charCodeAt(0);
        transformChar++;
        if(transformChar >= 122) {
            transformChar = 97;
        }
        tempStr[i] = String.fromCharCode(transformChar);
    }
    return tempStr.join('');
}

4. 회전 초밥 접시 종류

문제 설명

회전 초밥을 먹을 때, 접시들의 번호가 주어집니다.
이 중에서 임의의 연속된 접시를 선택하여 먹을 때, 가능한 모든 선택에서 가장 다양한 초밥 종류의 개수를 구하세요.

문제 풀이

Set 자료구조는 고유의 값을 저장하는 특징이 있다.
중복된 값이 들어와도 고유의 개수를 유지하기 때문에 Set 자료구조를 활용해서 구현했다.

전체 코드

function countDistinctMeals(arr) {
    let temp = new Set();
    for(let i=0; i<arr.length; i++) {
        temp.add(arr[i]);
    }
    return temp.size;
}

5. 가장 큰 수

문제 설명

양의 정수가 주어질 때, 숫자에서 k개의 자릿수를 제거하여 얻을 수 있는 가장 큰 수를 구하세요.

문제 풀이

  1. 자릿수를 제거해도 가장 큰 수가 되려면 앞에 0~9 중 가장 큰 값이 와야한다고 생각해서 정렬을 먼저 해줘야 겠다고 생각했다.
  2. 정렬이 된 상태에서 배열의 뒤에 있는 값을 k 만큼 pop()으로 빼주었다.
  3. 배열을 join 하여 반환값으로 주었다.

전체 코드

function getMaxNumber(num, k) {
    const numToArr = num.toString().split('').sort((a,b) => {return b-a;});
    for(let i=0; i<k; i++) {
        numToArr.pop();
    }

    console.log(numToArr.join(''));
}

2회차

1. 중복 문자 제거

문제 설명

주어진 문자열에서 중복된 문자를 제거하고, 남은 문자들을 원래 순서대로 반환하는 함수를 작성하세요.
ex) [a,b,c,d,a,b] => [a,b,c,d] 출력

문제 풀이

이 문제도 Set 자료구조를 사용했다.
사실 처음에 예시 출력이 없어서 중복된다면 모두 삭제하도록 했었는데 기존 값은 그대로 두고 이후 중복값만 제거하는 형식이어서 쉽게 구현했다.

전체 코드

function deleteDistinctStr(str) {
    const mySet = new Set();
    for(idx in str) {
        mySet.add(str[idx]);
    }

    return [...mySet].join('');
}

2. 최솟값, 최댓값

문제 설명

주어진 배열에서 최솟값과 최댓값을 찾고, [최솟값, 최댓값] 형태의 배열을 반환하는 함수를 작성하세요.

문제 풀이

배열 안에서의 최솟값 최댓값을 구하는 것이다.
각자 값을 저장할 변수가 있어야겠다고 생각했고, 해당 값에 최소,최대 값을 찾으려면 Math.min(), Math.max() 메서드를 사용해야 한다는 것이 떠올랐다.

mix() max() 메서드의 경우 파라미터로 숫자들을 전달 받는다.
즉, 배열 형태인(arr)로 받아버리게 되면 안되고 Spread Operator 를 사용하면 arr에 담긴 값들을 배열이 아닌 분해된 상태로 매개변수를 입력할 수 있다.

전체 코드

function getMinMax(arr) {
    let res=[];

    res[0] = Math.min(...arr);
    res[1] = Math.max(...arr);
    return res;
}

3. 문자열 요약

문제 설명

주어진 문자열을 요약하는 함수를 작성해주세요!
ex) 'aaabbccc' 입력 -> 'a3/b2/c3' 출력

문제 풀이

  1. 다른 종류의 값들을 카운트하는 방식은 뭘 쓰면 좋을까 하다가 객체를 떠올리게 되었다.

  2. 객체는 key:value 형태로 되어있기 때문에 만약 'aabbc' 가 주어진다면 'a' 알파벳의 키에 count값, 'b' 알파벳의 키에 count값, ... 이런식으로 주면 좋을 것 같았다.

  3. 그렇게 주어진 값은 템플릿 리터럴 방식을 통해 끝나는 곳에 '/' 를 붙여 res에 추가하는 방향으로 하였다.

  4. 마지막에 '/'는 없으니 slice 메서드를 통해 없애주었다.

전체 코드

function summationStr(str) {
    let distinctStr = {};
    let res='';

    for(let i = 0; i < str.length; i++) {
        if(distinctStr[str[i]] !== undefined) {
            distinctStr[str[i]]++;
        }
        else {
            distinctStr[str[i]] = 1;
        }
    }
    
    for(key in distinctStr) {
        res += `${key}${distinctStr[key]}/`;
    }

    res = res.slice(0, res.length-1);

    return res;
}

4. 두 수의 조합 찾기

문제 설명

주어진 배열에서 두 수를 선택하여 그 합이 주어진 target 값과 일치하는지 확인하는 함수를 작성하세요. 일치하는 경우 true, 그렇지 않은 경우 false를 반환하세요.

문제 풀이

  1. 일단 최대한 반복을 줄이고 싶어서 배열에 든 값이 target보다 크면 삭제하도록 하였다.
  2. 그리고 이중 반복문을 통해 각 숫자를 + 조합하여 target이 되는지 탐색했다.
  3. 만약 가능한 조합이 있다면 바로 return 하도록 하였다.

전체 코드

function findPlusTarget(arr, target) {
    const findArr = [];
    for(idx in arr) {
        if (arr[idx] < target) {
            findArr.push(arr[idx]);
        }
    }
    
    for(idx_first in findArr) {
        for(idx_second in findArr) {
            if(findArr[idx_first] + findArr[idx_second] === target) {
                return true;
            }
        }
    }

    return false;
}

5. 유효한 괄호 확인

문제 설명

주어진 문자열이 유효한 괄호 조합인지 확인하는 함수를 작성하세요.
유효한 조합은 모든 여는 괄호가 올바르게 닫혀야 하며, 괄호의 순서도 일치해야 합니다.
ex) '{[{[]}]}' 입력 -> true // '{[]])' -> false // '{}[[' -> false

문제 풀이

  1. 만약 str이 짝수가 아니라면 바로 false 처리를 하였다. -> 열고 닫기 한쌍이기 때문
if(str.length%2 !== 0)
        return false;
  1. 괄호의 뎁스를 확인하기 위한 stack을 선언하였다. let stack=0;

  2. 괄호는 짝꿍이 있다는 점을 생각해서 객체로 묶어보는 방법을 떠올렸다.

    const isValidClose = {
        ')': '(',
        '}': '{',
        ']': '['
    }
  1. 현재 괄호와 뎁스를 담기위한 객체도 선언했다.
let myParent = {};
  1. 이제부터 중요한데 str을 순회하면서 만약 { or [ or ( 라면 myParent 객체에 현재 인덱스와 문자를 넣어주었다. 인덱스는 뎁스를 확인하기 위한 것이고, 문자는 isValidClose 객체에서 한 쌍을 찾기 위해 저장해주었다. 뎁스 구분을 위해 stack도 증가시켜주었다.
for(idx in str) {
        if(str[idx] === '{' || str[idx] === '[' || str[idx] === '(') {
            myParent[stack] = str[idx];
            stack++;
        }
        ... (다음 로직)
}

5-1. 만약 } or ] or ) 라면 현재 저장된 뎁스의 괄호가 현재 문자의 괄호 열기 문자와 한 쌍인지 확인하는 검증을 하였다.

for(idx in str) {
        if(str[idx] === '}' || str[idx] === ']' || str[idx] === ')') {
            const matchParent = isValidClose[str[idx]];
            if(myParent[stack-1] === matchParent) {
                ...(5-2 로직)
            }
            else {
                ...(5-3 로직)
            }
        }
}

5-2. 한쌍이라면 저장된 뎁스의 괄호를 delete, stack을 감소
5-3. 아니라면 바로 false를 return 해주었다.

  1. 이렇게 순회가 끝나고 혹여나 마지막 문자에 괄호를 여는 것이 남아 있을 상황을 고려해서 stack이 0이 아니라면 false를 반환하도록 해주었다.
    if(stack !== 0) {
        return false;
    }

전체 코드

function isValidParentheses(str) {
    if(str.length%2 !== 0)
        return false;

    let stack=0;

    const isValidClose = {
        ')': '(',
        '}': '{',
        ']': '['
    }

    let myParent = {};

    for(idx in str) {
        if(str[idx] === '{' || str[idx] === '[' || str[idx] === '(') {
            myParent[stack] = str[idx];
            stack++;
        }

        if(str[idx] === '}' || str[idx] === ']' || str[idx] === ')') {
            const matchParent = isValidClose[str[idx]];
            if(myParent[stack-1] === matchParent) {
                delete myParent.stack;
                stack--;
            }
            else {
                return false;
            }
        }
    }

    if(stack !== 0) {
        return false;
    }

    return true;
}
profile
정의로운 사회운동가

0개의 댓글