알고리즘/백준

공부 143일차: 백준 13398번 연속합 2 자바 java

김발자~ 2022. 12. 20. 22:03
반응형

133398 연속합 2

 

https://www.acmicpc.net/problem/13398

 

13398번: 연속합 2

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

www.acmicpc.net

 

 

 


백준 13398번 문제 연속합 2


문제


 

 

 


과정 생각해보기 & 오답


 

https://gimbalja.tistory.com/251

 

공부 130일차: 백준 1912번 연속합 자바 java

1912 연속합 https://www.acmicpc.net/problem/1912 1912번: 연속합 첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작

gimbalja.tistory.com

위와 유사한 문제

수열에서 수를 하나 제거할 수 있느냐 없느냐가 다른 점이다

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.io.*;
import java.util.*;
 
public class Main {
 
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = null;
        
        int n = Integer.parseInt(br.readLine());
        
        int[] arr = new int[n];
        int[] dp = new int[n];
        int[] sum = new int[n];
        
        st = new StringTokenizer(br.readLine());
        for(int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
            dp[i] = arr[i];
        }
        
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < i+1; j++) {
                sum[i] += arr[j];    // sum[i]는 arr[0]~arr[i]까지의 누적합
            }
            //System.out.println(sum[i]);
        }
        
        // 원래 연속합
        for(int i = 1; i < n; i++) {
            dp[i] = Math.max(dp[i], dp[i-1]+arr[i]);
        }
        
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < i; j++) {
                // 누적합에서 중간수를 빼면 그 숫자를 삭제한 것과 같다
                dp[i] = Math.max(dp[i], sum[i]-arr[j]);
            }
        }
        
        Arrays.sort(dp);
        System.out.println(dp[n-1]);
    }
 
}
 
cs

 

예시로 주어진 수열은 정답과 같았지만, 채점은 오답으로 받은 코드다

기존처럼 연속합을 구한 뒤, i까지의 누적합에서 하나씩 빼보면서 가장 큰 수를 찾는 코드인데,

sum[i]가 무조건 처음부터 i번까지의 합을 가지므로 이게 매번 최대값일 리 없으므로 문제가 원하는 방식이 아니다

 

결국 오래 고민해보아도 방법이 떠오르지 않아

https://steady-coding.tistory.com/181

이 블로그를 참고했다

 

두 가지 방법을 소개하고 있는데, 이 중 왼쪽/오른쪽으로 나누어 구하는 방법이 재미있어 보였다

(다른 블로그들이 다 2차원 배열만 있기도 하고)

원리를 그림으로 표현하면 위와 같다

i를 제외한 연속합은 dpR[i-1] + dpL[i+1]가 되는 것이다

 

 

 


정답 인정 코드


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.io.*;
import java.util.*;
 
public class Main {
 
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = null;
        
        int n = Integer.parseInt(br.readLine());
        
        int[] arr = new int[n];
        int[] dpR = new int[n];
        int[] dpL = new int[n];
        
        st = new StringTokenizer(br.readLine());
        for(int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
            dpR[i] = dpL[i] = arr[i];
        }
        
        // 오른쪽 방향으로 최대 연속합 저장 (기존 연속합과 동일)
        int max = dpR[0];
        for(int i = 1; i < n; i++) {
            dpR[i] = Math.max(dpR[i], dpR[i-1]+arr[i]);
            max = Math.max(max, dpR[i]);    // 기존 연속합 최대값 구하기
        }
        // 왼쪽 방향으로 최대 연속합 저장
        for(int i = n-2; i >= 0; i--) {
            dpL[i] = Math.max(dpL[i], dpL[i+1]+arr[i]);
        }
        
        // 숫자를 아무것도 지우지 않았을 때(원래 연속합)랑 무언가를 지웠을 때 중 큰 값 산출
        for(int i = 1; i < n-1; i++) {
            int exceptI = dpR[i-1]+dpL[i+1];
            // arr[i]를 뺀 값 : dpR[i-1]+dpL[i+1] (i 전까지의 최대값 + i 후의 최대값)
            
            max = Math.max(max, exceptI);
        }
        System.out.println(max);
    }
 
}
cs

 

접근법이 새로워서 재밌었다

 

 

 

 


혼자 못 풀어서 아쉽다

골드 문제는 어렵구만

반응형