3 분 소요

서른 세 번째 포스팅

안녕하세요! 서른 세 번째 포스팅으로 찾아뵙게 되어 반갑습니다!♥

오늘의 포스팅 내용은 프로그래머스 - 햄버거 만들기에 관한 내용입니다.
자세한 내용을 알아보러 갑시다❗️

[Boongranii] Here We Go 🔥


1️⃣ 문제

[프로그래머스] 햄버거 만들기 (문제 링크)

💨 문제 설명

햄버거 가게에서 일을 하는 상수는 햄버거를 포장하는 일을 합니다. 함께 일을 하는 다른 직원들이 햄버거에 들어갈 재료를 조리해 주면 조리된 순서대로 상수의 앞에 아래서부터 위로 쌓이게 되고, 상수는 순서에 맞게 쌓여서 완성된 햄버거를 따로 옮겨 포장을 하게 됩니다. 상수가 일하는 가게는 정해진 순서(아래서부터, 빵 – 야채 – 고기 - 빵)로 쌓인 햄버거만 포장을 합니다. 상수는 손이 굉장히 빠르기 때문에 상수가 포장하는 동안 속 재료가 추가적으로 들어오는 일은 없으며, 재료의 높이는 무시하여 재료가 높이 쌓여서 일이 힘들어지는 경우는 없습니다.

예를 들어, 상수의 앞에 쌓이는 재료의 순서가 [야채, 빵, 빵, 야채, 고기, 빵, 야채, 고기, 빵]일 때, 상수는 여섯 번째 재료가 쌓였을 때, 세 번째 재료부터 여섯 번째 재료를 이용하여 햄버거를 포장하고, 아홉 번째 재료가 쌓였을 때, 두 번째 재료와 일곱 번째 재료부터 아홉 번째 재료를 이용하여 햄버거를 포장합니다. 즉, 2개의 햄버거를 포장하게 됩니다.

상수에게 전해지는 재료의 정보를 나타내는 정수 배열 ingredient가 주어졌을 때, 상수가 포장하는 햄버거의 개수를 return 하도록 solution 함수를 완성하시오.

💨 제한사항

  • 1 ≤ ingredient의 길이 ≤ 1,000,000
  • ingredient의 원소는 1, 2, 3 중 하나의 값이며, 순서대로 빵, 야채, 고기를 의미합니다.

💨 입출력 예

ingredient result
[2, 1, 1, 2, 3, 1, 2, 3, 1] 2
[1, 3, 2, 1, 2, 1, 3, 1, 2] 0

💨 입출력 예 설명

입출력 예 #1

  • 문제 예시와 같습니다.

입출력 예 #2

  • 상수가 포장할 수 있는 햄버거가 없습니다.

2️⃣ 문제 풀이

🔥 문제 풀이

  1. 1 - 빵, 2 - 야채, 3 - 고기
  2. 완전한 햄버거 -> 1-2-3-1
  3. 반복문을 순회하며 arr에 요소 삽입.
  4. 스택의 윗부분에서 4개를 자르는 slice(-4)를 사용하여 붙인값이 1231인지 확인.
  5. 맞으면 count 올려주고, 1231이었던 것은 splice를 사용하여 제거해줌.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function solution(ingredient) {
  let count = 0;
  const arr = [];

  for (let i = 0; i < ingredient.length; i++) {
    arr.push(ingredient[i]);

    if (arr.slice(-4).join("") === "1231") {
      count++;
      // arr.splice(-4)
      for (let i = 0; i < 4; i++) {
        arr.pop();
      }
    }
  }

  return count;
}

새로운 배열에 반복문을 순회하며 요소를 삽입하며 뒤에서 4개씩 잘라 그것이 '1231'과 같으면 카운팅 해주는 문제였다.

splice()for문을 둘 다 써서 돌려봤는데 시간 차이는 거의 없었다. 그러나 근소하게 for문이 조금 더 빨랐다.

splice()는 한 번의 메서드 호출로 여러 요소를 제거할 수 있고, for문을 사용한 pop()은 여러 번의 함수 호출이 발생한다.

GPT 피셜로는 splice()가 일반적으로 우세하다고 한다. 여러 번의 함수 호출이 발생하는 것보다는 한 번의 메서드 호출이 오히려 낫다는 말이다.

하지만 성능은 상황에 다를 수 있으며, 배열의 크기, 요소 수, 작업 환경을 고려하여 사용하면 된다고 한다. 일단 크기가 작은 편에 속하는 테스트 케이스에서는 for문을 활용한 것이 조금이나마 시간이 빨랐으니 알잘딱깔센하면 될 것 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
function solution(ingredient) {
  let count = 0;

  for (let i = 0; i < ingredient.length; i++) {
    if (ingredient.slice(i, i + 4).join("") === "1231") {
      count++;
      ingredient.splice(i, 4);
      i -= 3;
    }
  }

  return count;
}

위 코드는 어떤 사람이 푼 코드이다. 이 사람은 기존 배열을 통해 풀었다. 하지만, 인덱스를 계속 재설정하는 i-=3이 시간을 오래 잡아 먹는 것 같다.

나의 풀이

hamburger

인덱스 재설정 풀이

hamburger1

반복문에서 i의 값을 변경함으로써 반복의 흐름을 제어하고 있는데 이것은 반복문의 동작을 예측하기 어렵게 하며 버그를 발생시킬 가능성도 존재한다고 한다. 이런 방식은 반복문을 제어할 때 코드의 복잡성과 가독성이 떨어지며, 유지 보수하기 어렵다.

아, 물론. 이 분의 풀이를 평가하는 것은 절대 아니다. 단지, 내 궁금증을 해소하고 싶었기 때문에 찾아본 것 뿐이다.
혹여나, 저 코드의 작성자가 내 블로그를 볼 일은 없겠지만 만약 본다면 오해 없길 바라는 마음이다.


3️⃣ 느낀점

이 문제의 핵심은 splice() 였다고 생각한다.
잘 모르시는 분은 [Array.prototype.splice()-MDN] 이 곳을 참고해서 꼭 인지하길 바란다.

물론 나도 헷갈려서 찾아 보았지만 계속 사용할 문법은 꼭 익혀두는 것이 좋을 것이다. splice()는 시간이 오래 걸리는 원인 중 하나인데 뭐 시간 통과만 된다면 사용해도 상관은 없을 것으로 감히 판단 해본다.

요즘 문제를 풀고 이렇게 복습(?) 이라고 해야 하나. 암튼, 이렇게 찾아보고 정확히 파악하다 보니까 나만의 생각으로 적는 것이 재밌다. 요즘은 그냥 재밌어서 쓰는 것 같다. 그럼 안녕핑🐌

댓글남기기