공부/코딩테스트

[ 프로그래머스 C++ ] 연속 펄스 부분 수열의 합 - LV3

굥굔 2023. 5. 4. 13:07

< 해설 >

누적 합이라는 개념을 처음으로 알고 적용시킨 문제이다.

먼저 누적 합을 설명하자면 다음 그림과 같다.

인덱스 2의 누적합은 인덱스 0 + 1 + 2 까지의 값이다. 식으로 표현하면

S(n) = S(0) + S(1) + ... S(n-1) + S(n)  이라고 하는데 그냥 전까지의 합이라고 생각하면된다. 모든 배열의 값이 특정 인덱스까지의 합이므로 S(n+1) = S(n-1) + arr[n] 을 하면 된다. (S(n)은 n까지의 누적합.)

특정 인덱스에 대한 값만 구하고 싶다면 S(n) - S(n-1) 을 해주면 된다.

 

다시 문제로 돌아와서 보면 펄스값에 따라 값이 양수/음수 로 바뀐다. 근데 어짜피 절대값은 바뀌지 않으므로 최대, 최소 값만 구해주면 된다. 펄스값은 1, -1, 1 ... 이든 -1, 1, -1 .. 이든 둘중 아무거나 일단 적용해준다.

 

그렇게 고정된 배열에 누적합을 계산하고 누적합에서의 최대값과 최소값을 구해준다.

여기서 생각해 주어야하는 반례가 있다. 누적합이 아닌 그냥 인덱스의 값이 제일 큰 경우이다. 그래서 max함수로 maxi에서 mini를 뺀 절대값과 maxi 자체의 값을 비교해서 더 큰 값을 리턴해주면된다.

 

< 문제 >

 

< 풀이 >

#include <string>
#include <vector>
#include "string.h"

using namespace std;

long long solution(vector<int> sequence) {
    
    // 펄스는 어짜피 -1, 1 or 1 -1 순서.
    // 하나 만들어서 abs 해준다.
    long long AddNum1[500001];
    memset(AddNum1, 0, sizeof(AddNum1));
    
    for(int i=0; i < sequence.size(); i++)
    {
        if(i % 2 == 0)
        {
            AddNum1[i+1] = AddNum1[i] + sequence[i] * (-1);
        }
        else
        {
            AddNum1[i+1] = AddNum1[i] + sequence[i];
        }
    }
    
    long long maxi=0;
    long long mini=0;
    
    for(int i=0; i< sequence.size(); i++)
    {
        if(AddNum1[i+1] < mini)
            mini = AddNum1[i+1];
        
        if(maxi < AddNum1[i+1])
            maxi = AddNum1[i+1];
    }
    
    return max(abs(maxi-mini), maxi);
}

코드 실행결과. 누적합을 사용해야만 풀 수 있는 케이스들만 모아둔것 같다. ㅋㅋ