[프로그래머스] 1. 콜라 문제(Lv1), 2. [1차]뉴스 클러스터링(Lv2), 3. 위장(Lv2)

손규성·2022년 10월 24일
0

alogrithm

목록 보기
11/22
post-thumbnail

Lv. 1: 콜라 문제✍️


문제 설명

빈 병 a개를 가져다주면 콜라 b병을 주는 마트가 있을 때, 빈 병 n개를 가져다주면 몇 병을 받을 수 있는지 계산하는 문제입니다. 기존 콜라 문제와 마찬가지로, 보유 중인 빈 병이 a개 미만이면, 추가적으로 빈 병을 받을 순 없습니다. 상빈이는 열심히 고심했지만, 일반화된 콜라 문제의 답을 찾을 수 없었습니다. 상빈이를 도와, 일반화된 콜라 문제를 해결하는 프로그램을 만들어 주세요.

콜라를 받기 위해 마트에 주어야 하는 병 수 a, 빈 병 a개를 가져다 주면 마트가 주는 콜라 병 수 b, 상빈이가 가지고 있는 빈 병의 개수 n이 매개변수로 주어집니다. 상빈이가 받을 수 있는 콜라의 병 수를 return 하도록 solution 함수를 작성해주세요.

제한사항

  • 1 ≤ b < a ≤ n ≤ 1,000,000
  • 정답은 항상 int 범위를 넘지 않게 주어집니다.

나의 답안

function solution(a, b, n) {
    let answer = 0, leftover = parseInt(n/a) * b;

    while(true) {
        leftover = n - (parseInt(n / a) * a) + (parseInt(n/a) * b);
        answer += parseInt(n/a) * b;
        if(leftover < a) break;
        else n = leftover;
    }
    return answer;
}

접근 방식:

  1. while문이 한번 돌 때마다 각 변수가 어떻게 변하고 있는지 이해만 하면 어렵지 않은 문제이다. 특히 입출력 예 부분을 자세히 읽어보면 수학적 규칙도 이미 알려주기 때문에, 이에 맞게 단순히 코드만 작성하면 되는 문제이다.
  2. leftover 이라는 변수를 활용해 (A) while문에 break 조건을 걸어주었고, (B) 반납하고 남는 잔여 병수도 지속 업데이트 해주었다.
  3. while문이 한번 돌 때마다 n값은 업데이트 해주어 모든 수학적 규칙이 각 loop 별로 알맞게 돌아가게끔 했다.
  4. answer에는 반납 후 새로 받게 될 병수를 지속 업데이트해주었다.

회고:

  1. 문제에서 주어지는 예시들의 경우 모두 빈병 a개당 돌려주는 병 수b가 모두 1이었다. 처음엔 문제에 제공된 예시들에만 집중하다보니 b의 역할의 중요성을 느끼지 못했다. 그러다 보니 코드를 제출할 때마다 에러가 떴고, 코드에 b 값을 한번도 호출하지 않았다는 점을 깨닫고 나서야 고칠 수 있었다.


Lv. 2: [1차] 뉴스 클러스터링✍️


문제 설명

여러 언론사에서 쏟아지는 뉴스, 특히 속보성 뉴스를 보면 비슷비슷한 제목의 기사가 많아 정작 필요한 기사를 찾기가 어렵다. Daum 뉴스의 개발 업무를 맡게 된 신입사원 튜브는 사용자들이 편리하게 다양한 뉴스를 찾아볼 수 있도록 문제점을 개선하는 업무를 맡게 되었다.

개발의 방향을 잡기 위해 튜브는 우선 최근 화제가 되고 있는 "카카오 신입 개발자 공채" 관련 기사를 검색해보았다...(전체 읽기)

예제 입출력

str1str2answer
FRANCEfrench16384
handshakeshake hands65536
aa1+aa2AAAA1243690
E=M*C^2e=m*c^265536

나의 답안

function solution(str1, str2) {
    let arr1 = [], 
        arr2 = [];

    str1 = str1.toUpperCase();
    str2 = str2.toUpperCase();
    
    for (let i = 0; i < str1.length - 1; i++) {
        const str = str1.substr(i, 2);
        if (str[0] >= "A" && str[0] <= "Z" && str[1] >= "A" && str[1] <= "Z") arr1.push(str);
    }

    for (let i = 0; i < str2.length - 1; i++) {
        const str = str2.substr(i, 2);
        if (str[0] >= "A" && str[0] <= "Z" && str[1] >= "A" && str[1] <= "Z") arr2.push(str);
    }
  
    let intersection = [],
        union = [];

    for (let i = 0; i < arr2.length; i++) {
        if (arr1.indexOf(arr2[i]) >= 0) intersection.push(arr1.splice(arr1.indexOf(arr2[i]), 1));
        union.push(arr2[i]);
    }
  
    for (let i = 0; i < arr1.length; i++) {
        union.push(arr1[i]);
    }

    if (intersection.length === 0 && union.length === 0) return 65536;
    return parseInt(65536 * (intersection.length / union.length));
};

접근 방식:

  1. 대소문자 구분 없이 풀이가 되어야 하기 때문에 우선 매개변수 str1, str2 모두 대문자로 바꿔준다.
  2. 공백, 숫자 등 알파벳 외의 값이 포함되어 있는 쌍은 모두 무시해야 하기 때문에 각 for문에 조건문을 걸어준다.
  3. 각 교집합, 합집합 배열을 만들어주고, 반복되는 요소들에 대한 처리를 해준다.
  4. 마지막에는 교집합, 합집합 배열에 아무것도 들어있지 않는 예외의 경우 65536만 반환해주도록 한거나 or 제대로 교집합의 길이와 합집합의 길이를 나눠 제대로 된 값을 계산 및 반환하도록 한다.

회고:

  1. 이렇게 접근/풀이 방식이 선명하게 보이는데, 이렇게 오래 걸린 문제는 처음이다. 신경 써야할 부분이 많다 보니까 중간중간 내 워크플로우가 내 생각에 잠식되는 느낌이 났다.
  2. 처음에는 교집합, 합집합 개념 정석 그대로 접근하지 않아서 한번 코드를 다시 작성해야 했다. (그냥 처음부터 문제를 똑바로 천천히 읽어보고 풀이 시작하는게 훨씬 유리한 경우가 많다...)

Lv. 2: 위장✍️


문제 설명

스파이들은 매일 다른 옷을 조합하여 입어 자신을 위장합니다.

예를 들어 스파이가 가진 옷이 아래와 같고 오늘 스파이가 동그란 안경, 긴 코트, 파란색 티셔츠를 입었다면 다음날은 청바지를 추가로 입거나 동그란 안경 대신 검정 선글라스를 착용하거나 해야 합니다.

종류이름
얼굴동그란 안경, 검정 선글라스
상의파란색 티셔츠
하의청바지
겉옷긴 코트

스파이가 가진 의상들이 담긴 2차원 배열 clothes가 주어질 때 서로 다른 옷의 조합의 수를 return 하도록 solution 함수를 작성해주세요.

제한사항

  • clothes의 각 행은 [의상의 이름, 의상의 종류]로 이루어져 있습니다.
  • 스파이가 가진 의상의 수는 1개 이상 30개 이하입니다.
  • 같은 이름을 가진 의상은 존재하지 않습니다.
  • clothes의 모든 원소는 문자열로 이루어져 있습니다.
  • 모든 문자열의 길이는 1 이상 20 이하인 자연수이고 알파벳 소문자 또는 '_' 로만 이루어져 있습니다.
  • 스파이는 하루에 최소 한 개의 의상은 입습니다.

나의 답안

function solution(clothes) {
    let outfit = 0,
        type = [];
    
    for(let i = 0; i < clothes.length; i++) {
        type.push(clothes[i][1]);
    }

    let counts = {};
    type.forEach(function (x) { counts[x] = (counts[x] || 0) + 1; });
    
    let arr = [];
    for(let key in counts) {
        counts[key] += 1;
        arr.push(counts[key]);
    }

    for(let i = 0; i < arr.length; i++) {
        if(i === 0) outfit += arr[i];
        else {
            outfit *= arr[i];
        }
    }
    
    return outfit - 1;
}

접근 방식:

상의 2벌, 하의 1벌, 모자 1벌이 있다고 쳤을 때 옷의 조합의 수는 (2 + 1) x (1 + 1) x (1 + 1) - 1 으로 볼 수 있다. 종류별 갯수에 1을 더해주는 이유는 해당 종류의 의상을 입지 않을 수도 있기 때문이고, 마지막에 1을 빼주는 이유은 문제에 스파이는 최소 한 벌의 옷은 입어야 된다고 명시되어 있기 때문이다. 즉 스파이가 옷을 하나라도 입지 않은 경우는 없다.

  1. counts객체 안에 각 의상 종류를 key로, 각 key의 count를 value로 저장한다.
  2. 객체를 순회하며 각 value 값에 1을 더해주고, 이를 배열 안에 담아준다.
  3. for문을 통해 새로 생성된 배열을 순회하며, 인덱스 0일 때만 제외하고 현재 outfit 값에 arr[i]를 곱해준다.
    • 인덱스가 0일 때는 outfit 값이 0이므로 우선 arr[i] 값을 outfit 값에 더해준다.
  4. for문이 끝나면 누적된 outfit 값에서 1을 빼고 반환해준다.

회고:

  1. counts 객체에서 배열로 넘어가지 않고 해결하는 방법이 분명 있을 것 같은데, 객체 다루는 방법이 갑자기 잘 기억나지 않아서 결국 arr라는 배열을 새로 만들었다. 문제풀이 자체에는 큰 지장이 되지 않았지만 조금 더 간결하게 풀이할 수 있는 문제를 굳이 저렇게 길게 늘어놓고 나니 찝찝한 느낌이 드는 것은 사실이다.
profile
블로그 이사 → https://sqsung.tistory.com/

0개의 댓글