#1912 연속합
난이도 : 실버 2
유형 : DP
▸ 문제
n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.
예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.
▸ 입력
첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.
▸ 출력
첫째 줄에 답을 출력한다.
문제 풀이
연속 부분 구간 합 문제는 종만북에서도 한 번 다룬 문제이다. 왜냐하면 잘못 접근하면 O(N^3)이 되고 잘 설계하면 O(N)이 될 수 있기 때문이다.
구상
0번 인덱스부터 n-1인덱스까지 순차적으로 탐색하면서 합을 구해준다. 그런데 만약 이전 값이 음수라면 앞에 아무리 큰 수가 있더하더라도 더하는 것은 무의미하다. 차라리 앞의 큰 수 하나만 계산하는 것이 더 큰 값을 얻을 수 있다.
설계
- 이전 값이(cur)이 0보다 작으면 연속합을 현재 값으로 새로 갱신한다.cur = Math.max(0, cur) + num;
- 최대 연속 합이 갱신되는지 매번 체크해준다. max = Math.max(max, cur)
풀이 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
int cur =Integer.parseInt(st.nextToken());
int max =cur;
for(int i=1; i<n; i++) {
int num = Integer.parseInt(st.nextToken());
cur = Math.max(0, cur) + num;
max = Math.max(max, cur);
}
System.out.println(max);
}
}
잘못 접근한 예
이렇게 매번 새롭게 연속합을 계산해서 최댓값을 구하면 O(n^3)으로 시간초과가 발생한다.
int[] arr = new int[n];
for(int i=0; i<n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
int max = arr[0];
for(int i=0; i<n; i++) {
for(int j=i; j<n; j++) {
int sum=0;
for(int k=i; k<=j; k++) {
sum += arr[k];
}
max = Math.max(max, sum);
}
}
System.out.println(max);
'Dot Algo∙ DS > PS' 카테고리의 다른 글
[BOJ] 백준 4485번 녹색 옷 입은 애가 젤다지? (Java) (0) | 2021.08.23 |
---|---|
[BOJ] 백준 11727번 2xn 타일링 2 (Java) (0) | 2021.08.21 |
[BOJ] 백준 1932번 정수 삼각형 (Java) (0) | 2021.08.20 |
[BOJ] 백준 2250번 트리의 높이와 너비 (Java) (0) | 2021.08.19 |
[BOJ] 백준 1149번 RGB거리 - 트리 DP (Java) (0) | 2021.08.18 |