ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CodeKata] 위클리 프로그래머스(2월 1주차)
    Algorithm 2021. 2. 1. 16:31
    반응형

    🥋 Ooooth!! (Level 1)

    새벽작업이 많아지면서 10시 기상 약속을 자꾸 못지키고 있다. 내일부턴 점심전 1코드카타를 반드시 하겠다.

    다음주부턴 레벨2로 올릴건데, 오전 코드카타부터 밀리게 되면 하루 전체에 차질이 생기므로 2월의 첫날 나와의 약속이다!!


    👊 2.1(월) / 2016년

    📜 문제

     

    🧮 풀이

    function solution(a, b) {
        const dayArr = ['SUN','MON','TUE','WED','THU','FRI','SAT']
        const dayIndex = new Date(`2016-${a}-${b}`).getDay();
        
        return dayArr[dayIndex];
    }
    1. 요일값이 담긴 dayArr 를 선언한다. 여기서 정답요소를 인덱싱하여 찾을 것이다.
    2. dayIndex는 new Date() 객체와 getDay() 메서드를 사용했다. 먼저, new Date() 에 날짜를 입력하면 날짜정보를 반환한다.
    3. getDay()는 해당일의 요일을 인덱스로 반환한다.(일요일이 0, 월요일이 1 ... 토요일이 6이다.)

     

    🖇 리뷰

    function solution(a, b) {
        const day = new Date(`2016-${a}-${b}`).toString().slice(0,3).toUpperCase();
        return day;
    }

    더 많은 메서드로 간결하게 풀 수 있을것 같아 내가 새로 고안해본 방법이다!

    new Date() 반환값 맨 앞이 요일임을 감안해서, String 변환 -> 앞에 3글자 자르기 -> 대문자 변환 처리 후 반환한 것이다.


    👊 2.2(화) / 3진법 뒤집기

    📜 문제

     

    🧮 풀이

    function solution(n) {
        var answer = parseInt(n.toString(3).split("").reverse().join(""), 3)
        return answer;
    }
    
    1. [10진수].toString(3) : 10진수 -> 3진수 변환을 해준다. string 타입으로 반환
    2. split() - reverse() - join() : 위 문자열을 뒤집는다.
    3. parseInt([10진수], 3) : 3진수 -> 10진수로 변환해준다. number 타입으로 반환

     

    🖇 리뷰

    메서드들과, 특히 toString / parseInt가 진수변환이 된다는 것은 새로 알았지만, 알고리즘적 풀이는 아니라 생각됬다.

    아래 풀이는, while 반복문과 reduce 합계를 통해 정답을 도출하는 아주 유용한 답안이다.

    function solution(n) {
        const answer = [];
        while(n !== 0) {
            answer.unshift(n % 3);
            n = Math.floor(n/3);
        }
        return answer.reduce((acc,v,i) => acc + (v * Math.pow(3, i)),0);   
    }

     

    1. answer 배열의 요소들로 3진수 각 자리수를 담는다. 이 때, unshift로 앞으로 담으면서 뒤집는 효과를 동시에 도출했다.
    2. 3진수 자리수는 n(10진수)을 3으로 나눈 나머지로 계산했다. (9는 나머지가 0이므로 1자리 0, 8은 나머지가 2이므로 1자리 2)
    3. 다음 자리수를 구하려면 n(10진수)을 3으로 나눈 몫이 필요하다. (Math.floor) 이렇게 n을 3으로 나누며 0이 될 때까지 반복한다.
    4. 이렇게 모인 answer 배열의 값들을 10진수로 변환한다. reduce로 합을 구하고, Math.pow(3, 제곱수) 를 현재값(v)에 곱했다.

    👊 2.3(수) / 같은 숫자는 싫어

    📜 문제

     

    🧮 풀이

    function solution(arr) {
        var answer = [];
        answer.push(arr[0]);
        for (let i = 1 ; i < arr.length ; i++) {
            if (arr[i] !== arr[i-1]) {
                answer.push(arr[i])
            }
        }
        return answer;
    }
    1. 중복을 확인할 배열(arr)의 첫 요소를 우선 중복요소를 누적할 배열(answer)에 push한다.
    2. 이후, arr의 두 번째 요소부터 순회하며, 전 요소와 같지 않을 경우 answer에 누적을 계속한다.

     

    🖇 리뷰

    이전에, 위코드 코드카타에서 풀어본 로직이라 무난하게 풀 수 있었다.

    처음에는 !arr.includes(arr[i]) 조건문을 적용했는데, 그러면 중복되는 요소들까지 누적되지 않으므로 유념해야겠다!

    (예를 들면, 문제사진의 첫 번째 경우 답이 [1, 3, 0, 1] 인데, 위 조건문을 쓰면 [1, 3, 0] 이 된다.)


    👊 2.4(목) / 문자열 내 마음대로 정렬하기

    📜 문제

     

    🧮 풀이

    function solution(strings, n) {
        
      var answer = strings.sort((a,b) => {
        if (a[n] > b[n]) {
          return 1;
        }
        else if (a[n] < b[n]) {
          return -1;
        }
        else {
          return (a > b) ? 1 : -1;
        }
      });
        return answer;
    }
    1. sort() 메서드를 활용했다. strings 각 요소의 [n]번째 글자끼리 비교하면서, 앞글자가 느리면(>) 1(재배열), 빠르면(<) -1(고정)
    2. 두 글자가 같은 경우가 있다.(=), 이 때는, 전후 글자 자체를 비교하면 사전순으로 배열이 된다.  

     

    🖇 리뷰

    sort() 메서드로 쉽게 풀었지만, sort()의 세부 문법에 대해서 다시금 공부하게 된 좋은 계기였다.

    우선, sort() 자체로도 오름차순 정렬이 되지만, 내부 인자로 비교함수를 받을 수 있다는 것을 확실히 알게 되었다.

     

    a-b 양/음 판정을 통해 숫자 비교도 가능하고, 문자의 경우는 위처럼 비교 연산자를 통해 비교한다. (return 1, -1 을 해줘야 한다.)

    위 풀이에서, return 값이 0일 때(두 값이 같을 때), 별도의 처리가 없으면 기존 배열 순서가 적용되므로 위처럼 다시 글자자체를 비교해준 것이다.



    👊 2.5(금) / 소수 찾기

    📜 문제

    🧮 풀이

    도저히 풀지 못하고... 답안들을 오픈해봤다. Set() 에 대한 개념이 부족하여, 반복문으로 푼 것 중에 이해가 되는 풀이를 가져와봤다.

     

    🖇 리뷰

    function solution(n) { 
      let answer = 0; 
      let arr = []
      for (let i = 2; i <= n; i++) { 
        arr[i] = i; 
      }
      for (let i = 2; i <= n; i++) { 
        if (arr[i] === 0) 
          continue; 
        for (let j = i + i; j <= n; j += i) {
          arr[j] = 0; 
        }
      } 
      for (let i = 2; i <= n; i++) { 
        if (arr[i] !== 0) 
          answer++; 
      } 
      return answer 
    }
    1. arr 배열에 2부터 n까지 정수들을 모두 추가해준다. (숫자 = 인덱스)
    2. 2의 순서에서 보면, 2+2인 4부터 그 숫자(2)의 배수들을 모두 지워준다. 본인은 소수이기 때문에 남기고, *2인 i+i가 시작 인덱스
    3. 해당 순서의 숫자가 0이라면 이미 전에 지워졌으므로 continue로 다음 반복문으로 넘어간 것이다.
    4. arr에서 남은 0이 아닌 숫자(소수에 해당하는 숫자 혹은 인덱스)들의 합을 누적하여 answer 값을 반환한다.

    * 출처 : jo-c.tistory.com/38  

     


    👊 2.7(일) / 신규 아이디 추천(KAKAO) - 1단계 졸업 문제!

    본래 평일만 문제를 풀었지만, 내일부터 2단계로 넘어가기 위해 1단계 중 푼 사람이 1200명인 카카오 알고리즘 문제를 마지막으로 풀어보고 1단계를 마무리하고자 했다.

     

    📜 문제

     

    🧮 풀이

    function solution(new_id) {
      // 1단계 : 소문자 치환
      let answer = new_id.toLowerCase();
      // 2단계 : 한글, 특수문자 제거
      const regexCha =  /[~!@#$%^&*()=+{}:?\[\],<>\/]/g;
      const regexKor = /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/g;
      answer = answer.replace(regexCha, "");
      answer = answer.replace(regexKor, "");
      // 3단계 : 연속 . 제거
      const regexDot = /[.]{2,}/g;
      answer = answer.replace(regexDot, ".")
      // 4단계 : 처음과 끝 . 제거
      if (answer.startsWith('.')) {
        answer = answer.substr(1, answer.length-1)
      }
      if (answer.endsWith('.')) {
        answer = answer.substr(0, answer.length-1)
      }
      // 5단계 : 빈 String인 경우
      if (!answer) {
        answer = "a";
      }
      // 6단계 : 최대길이 준수
      if (answer.length >= 16) {
        answer = answer[14] === "." ? answer.substring(0, 14) : answer.substring(0,15)
      }
      // 7단계 : 최소길이 준수
      if (answer.length <= 2) {
        while (answer.length < 3) {
          answer += answer[answer.length - 1]
        }
      }
      return answer;
    }
    1. 소문자 치환: toLowerCase() 메서드를 쓰면, 모든 대문자가 소문자로 치환된다.
    2. 한글, 특수문자 제거: 정규식( /[대상문자]/ ) 부합 시, replace() 메서드로 해당 문자를 ""(빈 문자열)로 치환했다.
    3. 연속 '.' 제거 : 연속된 '.'을 하나로 치환했다. 정규식의, {[최소 반복수], [최대 반복수]} 문법을 활용했다.
    4. 시작, 끝 '.' 제거: startsWith(), endsWith() 메서드를 활용했다. 해당 문자열로 시작/끝 여부를 boolean 반환한다.
    5. 빈 String: 문자열이 빈 경우(!answer), "a"를 대입했다.
    6. 최대길이 준수: 길이가 16 이상인 경우, substring() 메서드로 잘랐다. 15번째 글자가 '.' 이라면 14번째까지만 자른다.
    7. 최소길이 준수: 길이가 2 이하인 경우, while 반복문으로 길이가 3보다 작은 동안(=3이 될때까지) 계속 끝글자를 더해줬다.

    * 본래, replaceAll()로 모든 문자를 검사 및 치환해야 했지만, 정규식 끝에 'g'가 모든 글자체크를 지시함.

     

    🖇 리뷰

    1단계에서 어려운(물론 푼 사람 기준이지만) 문제를 참고 없이 풀어내다보니 뿌듯하면서, 생각이 많이 바뀌는 계기가 되었다.

     

    나는 알고리즘을 풀면서, 알고리즘스러운(?) 풀이를 지향해야 한다고 생각했다. (조건문, 반복문, 기본 메서드 등등)

    하지만, 위 한문제에서 알게된 메서드만 해도 replace, startsWith, endsWith... 정규식 문법도 어느정도 공부하게 되었다.

     

    물론, 위 내용들을 반복문이나 조건문으로 대체할 수 있는 부분도 많다.

    하지만, 앞으로는 기본구현 방법은 머릿속으로 그리면서, 새로운 메서드나 문법을 공부하면서 풀이를 만들어나가 보려고 한다.

    반응형
Designed by Tistory.