왜 필요 한가?
for(int i=0; i<배열의 크기; i++){
arr[i] = scanner.nextInt();
}
/* 인덱스0부터 n-1 까지의 합을 구하라
시간 복잡도 O(N) */
해당 합을 시간 복잡도 O(1)로 구할 수 있는 방법
➡️ 구간 합 알고리즘
배열 arr을 입력 받기 전에 구간 합을 저장 할 배열 S를 생성해주고
배열 arr에 정수를 입력할때 배열 S에도 입력
이렇게 배열에 대한 합들을 기록.
Ex)
arr = [15,13,10,7,3,12]
S = [15,28,38,45,48,60]
배열 arr의 인덱스 2부터 4까지의 합을 구해라.
10 + 7 + 3 = 20 O(N)
arr[2] + arr[3] + arr[4]
배열 S를 통한 정답 구하기
S[4] - S[1] = 20 O(1)
인덱스 4까지의 합 - 인덱스 1까지의 합 = 인덱스 2~ 4까지의 합
🔍배열 구간에 대한 합을 구하는데 유용하다.
이때, BufferedReader를 사용 해야 한다.
BufferedReader가 Scanner를 사용 하는 것보다 빠르고, 문자열에 최적화 돼있기 때문.
BufferedReader
import java.io.BufferedReader;
import java.io.InputStreamReader;
1 2 3 4 5 6 7 8 9 10 11 12 // 한줄 입력
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s = br.readLine().split(" ");
// s[0] = "1"; Integer.parseInt(s[0]) => 1
// s[1] = "2";
// s[2] = "3";
// .....
StringTokenizer 사용목적
StringTokenizer 사용법
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in);
StringTokenizer st = new StringTokenizer(br.readLine());
// AB CDD EFFF GH 입력
st.nextToken() // AB
st.nextToken() // CDD
st.nextToken() // EFFF
st.nextToken() // GH
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class App2{
/*
br.readLine() 같이 파일처리 등 입출력 관련된 코드를 사용할땐
IOException 예외처리를 해줘야 한다.
*/
public static void main(String[] args) throws IOException{
//M이 100,000개 하면 그 안에서 System.out.println을 100,000개 불러야 하기 때문에
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
//수의 갯수
int N = Integer.parseInt(st.nextToken());
//합을 구해야 하는 횟수
int M = Integer.parseInt(st.nextToken());
/*
배열입력
int[] arr = new int[N];
*/
//구간 합 배열 (인덱스 1부터 시작)
int[] S = new int[N+1];
st = new StringTokenizer(br.readLine());
for(int i=1; i <= N; i++){
S[i] = S[i-1] + Integer.parseInt(st.nextToken());
}
//구간 합 출력
int left_th, right_th;
for(int i=0; i < M; i++){
st = new StringTokenizer(br.readLine());
left_th = Integer.parseInt(st.nextToken());
right_th = Integer.parseInt(st.nextToken());
sb.append(S[right_th] - S[left_th-1] + "\n");
}
System.out.println(sb);
}
}
Int 배열을 생성할때 초기화를 0으로 해준다는 굉장히 사소한 부분이 중요하다.
➡️ S[i] - S[i-1] 이 오류없이 잘 흘러가게 되는 이유
2차원 배열 구간 합 구하기
이 또한 주어진 배열 사이즈 N 크기보다 +1 큰 배열을 선언해주고
초기화가 저절로 0이 된다는 성질을 이용해서 푸는게 포인트다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int Dsum(int[][] D, int x1, int y1, int x2, int y2){
return ( D[x2][y2] - D[x2][y1-1] - D[x1-1][y2] + D[x1-1][y1-1]);
}
public static void main (String[] args) throws IOException{
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
//표의 크기
int N = Integer.parseInt(st.nextToken());
//합을 구해야 하는 횟수 M
int M = Integer.parseInt(st.nextToken());
//구간 합 2차원 배열
int[][] D = new int[N+1][N+1];
for(int i=1; i<N+1; i++){
st = new StringTokenizer(br.readLine());
for(int j=1; j<N+1; j++){
//구간합에서 배열+1 크기로 선언하면 굉장히 편해짐
D[i][j] = D[i-1][j] + D[i][j-1] - D[i-1][j-1] + Integer.parseInt(st.nextToken());
}
}
for(int i=0; i<M; i++){
st = new StringTokenizer(br.readLine());
sb.append(Dsum(D, Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken()),
Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken())) + "\n");
}
System.out.println(sb);
}
}