본문 바로가기
코딩 테스트/백준

13398 연속합2

by 위그든씨 2025. 1. 4.

n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다. 또, 수열에서 수를 하나 제거할 수 있다. (제거하지 않아도 된다)

예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 수를 제거하지 않았을 때의 정답은 12+21인 33이 정답이 된다.

만약, -35를 제거한다면, 수열은 10, -4, 3, 1, 5, 6, 12, 21, -1이 되고, 여기서 정답은 10-4+3+1+5+6+12+21인 54가 된다.

입력

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

출력

첫째 줄에 답을 출력한다.

====

문제 분석

인덱스가 최대 10만이므로 시간 복잡도는 N을 지향해야한다.

이 문제에서 특이점은 연속된 수 중 뺴고 싶은 것이 생긴다면 하나는 뺄 수 있다는 것이다.

만약 이러한 특이점이 없다면 dp를 선언 후 각 인덱스 별로 dp[i]= MAX(dp[i-1]+arr[i] , arr[i]) 라는 점화식을 사용하면 된다.

그렇다면 하나를 뺄 수 있다는 특이점을 사용할려면 

(이전까지 하나도 빼지않고 연속 된 수를 만든 것중 합이 제일 큰 값)과 (이전까지 한번은 빼고 온 연속 된 수를 만든 것 중 합이 제일 큰 값에 arr[i] 를 더한 값)을 비교하면 된다.

1. 이전까지 하나도 빼지 않았다는 것은 이번의 수는 뺄 수 있는 것므로 이전까지의 합을 그대로 가져오면 되고

2. 이전까지 한번은 빼고 온 연속 된 수를 만든 것 중 합은 이제는 뺄 수 있는 것이 아니므로 그 수에 현재 arr[i]를 무조건 더해야 하는 것이다.

dp 자체를 2개의 행으로 만들어서 첫번째 행에는 연속 된 수 중 한 번도 뺀 적이 없이 만든 제일 큰 합을 기록

두번째 행에는 연속된 수 중 중간에 하나는 제외하고 더한 제일 큰 합을 기록한다.

const dp = Array.from({ length: 2 }, () =>
        Array.from({ length: n }, () => 0)
    );

    dp[0][0] = arr[0];
    dp[1][0] = arr[0];

위에서 만든 것을 점화식으로 표현하면

dp[0][i] = Math.max(dp[0][i - 1] + arr[i], arr[i]);
dp[1][i] = Math.max(dp[0][i - 1], dp[1][i - 1] + arr[i]);

정답 코드

const main = (n, arr) => {
    const dp = Array.from({ length: 2 }, () =>
        Array.from({ length: n }, () => 0)
    );

    dp[0][0] = arr[0];
    dp[1][0] = arr[0];

    for (let i = 1; i < n; i++) {
        dp[0][i] = Math.max(dp[0][i - 1] + arr[i], arr[i]);
        dp[1][i] = Math.max(dp[0][i - 1], dp[1][i - 1] + arr[i]);
    }
    console.log(Math.max(Math.max(...dp[0]), Math.max(...dp[1])));
};

const input = require('fs')
    .readFileSync(process.platform === 'linux' ? '/dev/stdin' : './input.txt')
    .toString()
    .trim()
    .split('\n');

const n = +input[0];
const arr = input[1].split(' ').map((v) => +v);
main(n, arr);

'코딩 테스트 > 백준' 카테고리의 다른 글

2293 동전1  (0) 2025.01.06
16932 모양 만들기  (0) 2025.01.04
5557번 1학년 (자바스크립트)  (0) 2025.01.04
12869 뮤탈리스크  (0) 2025.01.03
2133 타일 채우기  (0) 2025.01.03