ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프로그래머스 코딩테스트 - 스티커 모으기(2)
    코딩테스트 풀이 2024. 11. 20. 16:32
    728x90

    문제 설명

    N개의 스티커가 원형으로 연결되어 있습니다. 다음 그림은 N = 8인 경우의 예시입니다.


    원형으로 연결된 스티커에서 몇 장의 스티커를 뜯어내어 뜯어낸 스티커에 적힌 숫자의 합이 최대가 되도록 하고 싶습니다. 단 스티커 한 장을 뜯어내면 양쪽으로 인접해있는 스티커는 찢어져서 사용할 수 없게 됩니다.

    예를 들어 위 그림에서 14가 적힌 스티커를 뜯으면 인접해있는 10, 6이 적힌 스티커는 사용할 수 없습니다. 스티커에 적힌 숫자가 배열 형태로 주어질 때, 스티커를 뜯어내어 얻을 수 있는 숫자의 합의 최댓값을 return 하는 solution 함수를 완성해 주세요. 원형의 스티커 모양을 위해 배열의 첫 번째 원소와 마지막 원소가 서로 연결되어 있다고 간주합니다.

    제약 사항

    • sticker는 원형으로 연결된 스티커의 각 칸에 적힌 숫자가 순서대로 들어있는 배열로, 길이(N)는 1 이상 100,000 이하입니다.
    • sticker의 각 원소는 스티커의 각 칸에 적힌 숫자이며, 각 칸에 적힌 숫자는 1 이상 100 이하의 자연수입니다.
    • 원형의 스티커 모양을 위해 sticker 배열의 첫 번째 원소와 마지막 원소가 서로 연결되어있다고 간주합니다.

    해결 방법

    아이디어

    첫 아이디어 - index를 짝홀로 나눠어 더하자!

    홀수번째의 숫자를 모두 더하고 짝수 번쨰의 숫자를 모두 더해서 비교한다.

    단순히 양옆의 스티커를 제거하지 못하고 건너뛰기 때문에 홀수와 짝수로 나눠 더하면 될 것 같았다. 더군다나 예제 문제가 하필 이 방식으로 풀려서 정답일 줄 알았다.

    그러나 정답이 아니어서 혼란이 왔었다...

    정답 아이디어 - DP를 활용하자!

    다른 사람들의 질문을 보며 반례를 찾을 수 있었다.

     

    [1,1,22,1,1,33]

    이런 배열이 들어오게 된다면 첫 번째 아이디어로는 최대가 35가 된다. 하지만 실재로 최대는 55이 된다.

     

    따라서 동적 계획법을 사용해서 스티커를 순회하며 연속하지 않게 스티커의 합을 구한 뒤 더 큰 값을 저장해주면 된다.

     

    스티커 배열을 순회할 때 비교 대상은 (현재 스티커 + 전전스티커까지의 합)과 (전 스티커까지의 합)이다.

    이때, 중요한 것은 시작을 첫 번째 스티커 포함하는지 첫 번째 스티커를 포함하지 않는 지이다.

    계산과정은 아래 그림과 같다.

    알고리즘을 순서를 작성해보면

    • 길이가 1인 경우 => 무조건 그 숫자가 최대가 됨
    • 길이가 2인 경우 => 첫 번쨰 수와 두 번쨰 수를 비교해서 큰 값 반환
    • 그 이상인 경우
      • dp0: 첫 번째 인자부터 시작
      • dp1: 두 번째 인자부터 시작
      • 나머지 스티커를 순회하며
        • 스티커 합 비교
      • 두 dp의 결과 비교

    코드

    function solution(sticker) {
        const length = sticker.length 
        const first = sticker.shift();
        
        if (length === 1) return first;
        
        const second = sticker.shift();
        
        if (length === 2) Math.max(first, second);
        
        const dp0 = [first, first]
        const dp1 = [0, second]
    
        sticker.forEach((s, i) => {
            if (i !== length - 3) {
                dp0[i + 2] = Math.max(dp0[i+1], dp0[i] + s)
            }
            dp1[i + 2] = Math.max(dp1[i+1], dp1[i] + s)
        })
        
        const max0 = dp0.pop();
        const max1 = dp1.pop();
    
        return Math.max(max0, max1);
    }

    결과

    728x90

    댓글

Designed by Tistory.