🟦 백준 13398번. 연속된 정수의 합 구하기
https://www.acmicpc.net/problem/13398
문제
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보다 작거나 같은 정수이다.
출력
첫째 줄에 답을 출력한다.
풀이
이 문제는 A[] 배열에 음수가 포함이 되고 한개의 수를 제거할 수 있는 선택권이 존재한다.
이 선택을 할지 말지는 i값을 제거했을 때의 합 vs i값 포함했을 때의 합 중 최댓값을 비교하여 결정할 거다.
1) A[] 배열에는 기존 입력 데이터들을 저장한다.
2) 포인트는 ‘연속된 합’ max 값 (단, 1개 제거는 선택) 이다.
여기서 사용할 배열은 L[], R[] 배열이다.
우선, L[] 배열 세팅 방식
L[i] : 오른쪽 방향으로 i값 포함한 최대 연속합 저장용
L[0] = A[0] 값으로 초기화
for(int i=1 ~ N)
L[i] = Math.max(A[i], L[i-1] + A[i]);
//즉, 그냥 현재 A[i]값 vs 직전 L값합에 현재 i를 포함값
중에서 더 큰 값으로 세팅하는 거다.
result = Math.max(result, L[i]);// 여기에는 하나도 제거 안했을 때 최댓값을 저장
R[]배열 세팅 방식
R[N-1] = A[N-1] //끝 값을 세팅
for(int i=N-2 ~ 0) //거꾸로 돌면서
R[i] = Math.max(A[i], R[i+1] + A[i]);
//즉, 기존 i값 vs R의 값 + A[] 비교하여 최댓값 저장
}
- L[]배열에는 왼→오 방향으로 각 i를 포함하였을 때 최대 연속 합을 저장했다. 연속합 보다 기존 값이 더 크면 그냥 기존값으로 세팅하는 방식으로.
- R[]배열에는 오→왼 방향으로 각 i를 포함하였을 때 최대 연속합을 저장했다.
- 이제 마지막으로 해야 할 일은 각각의 i값을 제거하였을 때
L[i-1] + R[i+1] 값이 기존 result (max) 보다 큰 경우 갱신해주는 일이다.
이 작업을 통해 1개의 값을 제거했을 때 더 큰 값이 나타나면 그렇게 제거하는 선택을 구현한다.
풀이(코드) :
result + \n 개행 문자 넣어줘야 정답 처리 된다.
1) BufferedReader + Writer 버전
package to_0714_7;
import java.io.*;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int N = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
int[] A = new int[N];
for (int i = 0; i < N; i++) {
A[i] = Integer.parseInt(st.nextToken());
}
// 오른쪽 방향으로 index를 포함한 최대 연속 합 구하기.
int[] L = new int[N];
L[0] = A[0];
int result = L[0];
for (int i = 1; i < N; i++) {
L[i] = Math.max(A[i], L[i - 1] + A[i]);
result = Math.max(result, L[i]); // 하나도 제거 하지 않았을 때를 기본 최대값으로 저장
}
// 왼쪽 방향으로 index를 포함한 최대 연속 합 구하기.
int[] R = new int[N];
R[N - 1] = A[N - 1];
for (int i = N - 2; i >= 0; i--) {
R[i] = Math.max(A[i], R[i + 1] + A[i]);
}
// L[i - 1] + R[i + 1] 두개의 구간합 배열을 더해주면 i번째 값을 제거한 효과를 얻음
for (int i = 1; i < N - 1; i++) {
int temp = L[i - 1] + R[i + 1];
result = Math.max(result, temp);
}
bw.write(result + "\\n");
bw.flush();
bw.close();
br.close();
}
}
2) Scanner + System.out.println() 이떄 개행 포함
import java.util.Scanner;
/*연속합 다시 풀이 */
public class Main {
//실행 메인
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner kb = new Scanner(System.in);
int N =kb.nextInt();
int[] A = new int[N];
//데이터 입력받기
for(int i=0; i<N; i++) {
A[i]= kb.nextInt();
}
int result = A[0];//얘로 i포함한 연속합 최댓값 찍을 거임
//L[] 데이터 처리
int[] L = new int[N];
L[0]= A[0];
for(int i=1; i<N; i++) {
L[i] = Math.max(A[i], L[i-1]+A[i]);
result = Math.max(result, L[i]);
}
//R[] 데이터 처리
int[] R = new int[N];
R[N-1] = A[N-1]; //오른쪽 끝 데이터 초기화
for(int i=N-2; i>=0; i--) {
R[i]= Math.max(A[i], R[i+1]+A[i]);
}
//이제 i로 전체 순회하며 값 찍고, 그 값 제외한 값이 기존 result보다 크면 갱신
for(int i=1; i<N-1; i++) {
int tmp = L[i-1] + R[i+1];
result = Math.max(result, tmp);
}
System.out.println(result + "\\n"); //개행문자 포함하여 답 출력
}
}
'코딩 테스트 [준비] > [문풀] Baekjoon_백준 문풀_조지기' 카테고리의 다른 글
백준 | 1699번. 제곱수의 합 - DP 문제 (0) | 2023.08.02 |
---|---|
백준 | 11055번. 가장 큰 증가하는 부분수열 - DP 문제 (0) | 2023.08.01 |
백준 | 1915번. 가장 큰 정사각형 찾기 - DP 문제 (0) | 2023.07.14 |
백준 | 9252번. LCS - 최장 공통 부분 수열 찾기 - DP 문제 (0) | 2023.07.14 |
백준 | 10844번. 계단 수 구하기 - DP 문제 (0) | 2023.07.12 |