[백준 silver2] 연속합(1912)

이민선(Jasmine)·2023년 3월 19일
1

문제

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

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

입력

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

출력

첫째 줄에 답을 출력한다.

예제 입력 1

10
10 -4 3 1 5 6 -35 12 21 -1

예제 출력 1

33

예제 입력 2

10
2 1 -4 3 4 -4 6 5 -5 1

예제 출력 2

14

예제 입력 3

5
-1 -2 -3 -4 -5

예제 출력 3

-1

나의 코드

let input = require("fs")
  .readFileSync("/dev/stdin")
  .toString()
  .trim()
  .split("\n");
input.shift();
let nums = input[0].split(" ").map(Number);

let ans = [];
nums.forEach((num, i) => {
// index가 0인 원소는 일단 push하고 시작
  if (i === 0) {
    ans.push(num);
    return;
  }

// ans의 마지막 원소는 현재까지 누적된 값을 의미.
  const sum = ans[ans.length - 1] + num;
  ans.push(Math.max(sum, num));
});
console.log(Math.max(...ans));

오늘부터 본격적으로 DP 공부 시작!
메모이제이션을 처음 배우고 신세계를 맛보고 있다 ㅎㅎㅎㅎ
한 번 계산한 것은 메모해놓았다가 해당 값이 필요할 때 다시 계산하지 않고 메모한 값을 불러오는 기법!
시간복잡도를 줄이는 데에 굉장히 유용하다. (피보나치 수열이 대표적)
엄청 어려운 그런 기법일 줄 알고 쫄았는데 막상 배워보고 나니 어려운 문제들을 덜 어렵게 만들어주는 고마운 기법이다.

이 문제도 메모이제이션을 이용하여 풀어봤다.
nums 배열을 순회하며 각 차례에서 sum과 num의 비교 작업을 한다.
num은 현재 값이고, sum은 앞의 값들의 누적에 현재값을 더해준 값이다.
num이 음수일 수도 있으므로 num과 sum의 상대적 크기는 비교해봐야 알 수 있다.
만약 sum > num이라면 나의 메모장인 ans 배열에 sum을 push하고, num > sum이라면 그동안의 sum은 없었던 것으로 하고 새로운 sum을 만들어가기 위해 num을 push한다.

이렇게 하면 nums 배열의 원소 개수와 동일한 ans 배열이 만들어지는데, 여기서 가장 큰 값을 반환하면 된다.

고마운 메모이제이션~~ 앞으로도 더 많은 dp를 풀어보자!! 화이팅!!


띠용? 메모하고 광명 찾자면서 왜 점화식을 안쓰고 저렇게 풀었었지?
오늘은 2023년 8월 23일. 복습하러 왔슴당~

from sys import stdin as s

s = open("input.txt", "rt")  # 주석 처리해야 하는 부분

n = int(s.readline())

nums = list(map(int, s.readline().split()))

dp = [0] * n

for i in (range(0, n)):
    dp[i] = max(dp[i - 1] + nums[i], nums[i])

print(max(dp))

점화식 세워서 간단히 해결!
누적해나갈 것이냐, 지금 값부터 다시 시작할 것이냐.
를 선택하는 것이다.

profile
기록에 진심인 개발자 🌿

0개의 댓글