codingtest

연속 펄스 부분 수열의 합

2025-10-08
3분 분량
JAVA프로그래머스

문제 링크

문제 풀이 시간 : 1시간

문제 요약

  • 정수 수열 sequence가 주어짐
  • 연속된 일부 구간(부분 수열)을 선택하고 같은 길이의 펄스 수열을 각 원소에 곱함
  • 펄스 수열은 두 가지 형태 중 하나
  • 곱셈 결과로 만들어진 연속 펄스 부분 수열의 합 중 가장 큰 값을 구하기

문제 풀이

처음 이 문제를 보고 부분 합을 구해야겠다는 생각을 하고 일단 1로 시작하는 펄스 수열과 -1로 시작하는 펄스 수열을 각각 곱해서 순차합을 구해보았다.

예시와 같이 [2, 3, -6, 1, 3, -1, 2, 4] 라는 수열이 있을 때, 1과 -1로 시작하는 펄스 수열을 곱하면 아래와 같다.

  • 1로 시작하는 펄스 수열을 곱한 경우 : [2, -3, -6, -1, 3, 1, 2, -4]
  • 1로 시작하는 펄스 수열을 곱한 경우 : [-2, 3, 6, 1, -3, -1, -2, 4]

그리고 각 수열의 순차 합은 아래와 같다.

  • 1로 시작하는 펄스 수열을 곱한 경우 : [2, -1, -7, -8, -5, -4, -2, -6]
  • 1로 시작하는 펄스 수열을 곱한 경우 : [-2, 1, 7, 8, 5, 4, 2, 6]

이 두가지 수열을 자세히 살펴보면 그냥 부호가 반대이고 동일한 수열인 것을 알 수 있다!

그래서 우리는 한가지 경우에 대해서만 계산하고 절댓값을 통해 최대 부분 수열의 합을 구할 수 있다.

그러면 이제 최대 부분 수열의 합을 구하는 것이 문제인데

이건 아주 쉽다.

우리는 이미 연속된 부분 수열의 합을 구해두었기 때문에 그런 부분 수열의 합 중에서 가장 큰 것과 작은 것을 빼주면 되는 것이다.

위의 1로 시작하는 펄스 수열에서 가장 큰 값은 2이고, 가장 작은 값은 -8 이므로 두가지 값을 빼주면 10이라는 최댓값이 나오게 된다.

초기 코드

java
import java.util.*;

class Solution {
    public long solution(int[] sequence) {
        long answer = 0;
        int len = sequence.length;
        long[] sum = new long[len+1];
        
        sum[0] = sequence[0];
        sum[len] = 0;
        for(int i=1;i<len;i++){
            if(i%2==0)
                sum[i] = sum[i-1]+sequence[i];
            else
                sum[i] = sum[i-1]-sequence[i];
        }
        
        Arrays.sort(sum);
        answer = sum[len] - sum[0];
        
        return answer;
    }
}

처음엔 위와 같이 코드를 작성했다.

물론 이 코드도 동작하고 통과하는 코드이지만 생각해보니 이렇게 sum 배열을 계산하고, 정렬을 하는 불필요한 동작이 필요가 없었다!

최종 코드

java
class Solution {
    public long solution(int[] sequence) {
        long answer = 0;
        int len = sequence.length;
        
        long max = 0L;
        long min = 0L;
        long sum = 0L;
        for(int i=0;i<len;i++){
            if(i%2==0)
                sum += sequence[i];
            else
                sum -= sequence[i];
            
            max = Math.max(max, sum);
            min = Math.min(min, sum);
        }
        
        return max - min;
    }
}

또 다른 풀이

이 문제는 당연히 다른 방식으로도 풀 수 있다.

부분 수열의 합을 구하는 방법에는 Kadane 알고리즘이 있다.

Kadane 알고리즘에 대한 설명은 블로그에 정리해두었다.

Kadane 알고리즘 코드

java
class Solution {
    public long solution(int[] sequence) {
        long answer = 0L;
        long dp0 = 0L; // 1로 시작하는 펄스수열을 곱한 수열의 최대 부분합
        long dp1 = 0L; // -1로 시작하는 펄스수열을 곱한 수열의 최대 부분합

        for (int i = 0; i < sequence.length; i++) {
            if ((i & 1) == 0) { // 짝수 인덱스
                dp0 = Math.max(0L, dp0) + sequence[i];
                dp1 = Math.max(0L, dp1) - sequence[i];
            } else {            // 홀수 인덱스
                dp0 = Math.max(0L, dp0) - sequence[i];
                dp1 = Math.max(0L, dp1) + sequence[i];
            }
            answer = Math.max(answer, Math.max(dp0, dp1));
        }
        return answer;
    }
}

함께 읽으면 좋은 글

코딩 테스트2026-08-23

택배상자

order 배열은 택배 기사님이 원하는 상자 적재 순서다 기존 컨테이너 벨트는 1번부터 순서대로만 꺼낼 수 있다 보조 벨트는 스택처럼 마지막에 넣은 것부터 꺼낼 수 있다 원하는 순서대로 최대한 실을 수 있는 상자 개수를 구하는 문제다 처음에는 기존 벨트를 실제 리스트로 만들어…

코딩 테스트2026-08-23

롤케이크 자르기

topping 배열은 롤케이크에 일렬로 올라간 토핑 번호다 한 지점을 잘라 두 조각으로 나눴을 때, 양쪽 토핑 종류 수가 같아야 공평하게 나눈 것이다 공평하게 자를 수 있는 방법의 수를 구하는 문제다 처음에는 자르는 위치마다 왼쪽과 오른쪽 배열을 나눠서 각각 서로 다른 토핑…

코딩 테스트2026-08-23

할인 행사

want, number 배열로 정현이가 원하는 제품과 수량을 표현한다 discount 배열은 XYZ 마트가 매일 할인하는 제품 목록이다 연속된 10일 동안 할인 제품 종류와 수량이 want, number와 정확히 일치해야 회원가입할 수 있다 그런 시작일이 총 몇 번 있는지…

코딩 테스트2026-08-23

숫자 변환하기

자연수 x를 y로 바꾸는 데 x+n, x2, x3 세 가지 연산을 쓸 수 있다 x를 y로 바꾸는 최소 연산 횟수를 구하는 문제다 만들 수 없으면 -1을 반환한다 처음에는 x에서 시작해서 세 가지 연산을 재귀적으로 다 시도해보고 y에 도달하는 경로 중 가장 짧은 걸 고르면…