백준 13398번: 연속합2 - javascript

2 분 소요

백준 13398번: 연속합2

문제 설명

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보다 작거나 같은 정수이다.

출력

첫째 줄에 답을 출력한다.

접근

이 문제는 1912번 연속합의 응용 버전이다. 한 번 풀어봤던 문제가 베이스여서 금방 풀 줄 알았는데 시간을 꽤 많이 잡아먹었다…
문제에서 수열에서 수를 하나 제거할 수 있다.(제거하지 않아도 된다) 라는 조건이 붙었는데, 당연히 제거하고 싶은 수는 음수라고 생각해서 가볍게 주어진 배열에서 음수의 인덱스만 담은 배열을 만들고 그 배열을 reduce로 돌리면서 N번의 탐색을 개시했다.
당연히 결과는 시간초과가 나왔다…

그렇다면 어떻게 이번에 뛸 음수랑 다음에 건너뛸 음수의 경우간의 max를 비교할 수 있을까?..
한참 생각해도 시간초과를 통과할 방법이 생각이 안났는데, 다른 곳에서 힌트를 찾았다.
이제보니 너무 문제를 어렵게 생각했다.
잘 보면 수열에서 수를 하나 제거할 수 있다고 했다. 제거하지 않아도 되고 말이다.
그 뜻은 결과를 수를 제거한 경우와 수를 제거하지않은 경우 2가지다 끌고 가면 되는 뜻이였다.

즉, 표를 이렇게 만들어 풀면된다.

  10 -4 3 1 5 6 -35 12 21 -1
제거 안 한 경우 10 6 - - - - - - - -
제거 한 경우 10 10 - - - - - - - -

이 표를 이용하면 우리는 -4와 -35에서 어떻게 선택 할 건지 생각해봐야된다.
예를 들어 -4의 경우 제거를 안한 경우는 -4보다 10+(-4)가 크니깐 6이 될 것이고,
제거를 하는 경우는 제거를 한 10이 제거를 안한 10+(-4)보다 크니깐 10을 가져올 것이다.
그런데 이때 가져오는 10이란것은 제거 한 경우의 0번째 항의 10이 아니라 제거를 안 한 경우의 10이다.
왜냐? 제거를 한다고 치면 당연히 그 이전까지는 제거를 안했어야 한다. 그러므로 i-1번째까지 제거를 안 한 경우의 max값을 가져와야 하는게 맞다.

  10 -4 3 1 5 6 -35 12 21 -1
제거 안 한 경우 10 6 9 10 15 21 -14 12 33 32
제거 한 경우 10 10 13 14 19 25 21 33 54 33

이런 식으로 표가 나오게된다.
여기서 음수마다 [제거 한 경우]의 i번째 항은 [제거 안 한 경우]의 i-1번재 항의 값을 가져와 건너뛰었음을 알 수 있다.
image
그리고 당연히 결과물이 2가지가 되었으니 max값도 각 i번재 마다 제거를 안 한 경우와 제거를 한 경우를 2가지와 기존의 max값을 비교해서 저장하여 최종적인 max값을 반환해주면 된다.

정답 코드

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
let input = [];
rl.on('line', function (line) {
  input.push(line)
})
  .on('close', async function () {
  // 답안 작성
  let answer = '';
  let n = input[0];
  let arr = input[1]
  arr = arr.split(' ')  
  answer = continuity_sum(n, arr);
  
  console.log(answer)
  process.exit();
});

function continuity_sum(n, arr){
  let result = [];
  for(let i=0;i<n;i++){
    result.push([0,0])
  }
  result[0][0] = arr[0]*1;
  result[0][1] = arr[0]*1;
  let max = arr[0];
  for(let i = 1; i < arr.length; i++){
    result[i][0] = result[i][1] = arr[i]
    result[i][0] = Math.max(arr[i]*1, arr[i]*1+result[i-1][0]*1);
    result[i][1] = Math.max(result[i-1][0]*1, result[i-1][1]*1+arr[i]*1)
    max = Math.max(max, result[i][0], result[i][1]);
  }
  return max;
}

댓글남기기