수들의 합2_2003
링크 : https://www.acmicpc.net/problem/2003
2003번: 수들의 합 2
첫째 줄에 N(1 ≤ N ≤ 10,000), M(1 ≤ M ≤ 300,000,000)이 주어진다. 다음 줄에는 A[1], A[2], …, A[N]이 공백으로 분리되어 주어진다. 각각의 A[x]는 30,000을 넘지 않는 자연수이다.
www.acmicpc.net
문제 설명
N개의 수로 된 수열 A[1], A[2], …, A[N] 이 있다. 이 수열의 i번째 수부터 j번째 수까지의 합 A[i] + A[i+1] + … + A[j-1] + A[j]가 M이 되는 경우의 수를 구하는 문제이다.
문제 풀이
생각 과정
우선 떠오른 방법은 누적합을 이용하는 방법이다.
0번 인덱스부터 N-1인덱스까지 누적합을 구하고 i번째 누적합에서 0부터 i-1번째 인덱스까지의 값을 일일이 빼주는
방식으로 구현을 했다.
그 다음으로 떠올린 방법은 투포인터이다.
시작점과 끝점을 정하고 합이 M보다 작으면 끝점을 뒤로 이동시켜 합에 더해주고
M보다 크면 시작점을 앞으로 하나 당겨서 합에서 빼주는 방식으로 구현을 했다.
구현 - 누적합
public class 수들의합2 {
public static void main(String[] args) throws IOException {
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[] A = new int[N];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) { // 주어진 수 배열 A
A[i] = Integer.parseInt(st.nextToken());
}
int[] sum = new int[N]; // 누적합 배열 sum
sum[0] = A[0];
for (int i = 1; i < N; i++) {
sum[i] = A[i] + sum[i - 1]; // 누적합 계산
}
int cnt = 0;
for (int i = 0; i < N; i++) {
if (sum[i] == M) { // 누적합이 M과 같으면 cnt증가
cnt++;
}else {
int temp = sum[i];
for (int j = 0; j < i; j++) {
temp -= A[j]; // 누적합에서 하나씩 빼주며 계산
if (temp == M) { // 빼준 값이 M과 같으면
cnt++; // cnt 증가하고 종료
break;
}
}
}
}
System.out.println(cnt);
}
}
구현 - 투포인터
public class 수들의합2_2003_투포인터 {
public static void main(String[] args) throws IOException {
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[] A = new int[N];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
A[i] = Integer.parseInt(st.nextToken());
}
int cnt = 0; // 경우의수
int start = 0; // 시작점
int end = 0; // 끝점
int sum = 0; // 합
while (true) {
if (sum >= M) { // 합이 M보다 크거나 같으면
sum -= A[start++]; // sum에서 빼주고 시작점 앞으로
} else if (end >= N){ // 전부 탐색한 경우 종료
break;
} else { // 합이 M보다 작으면
sum += A[end++]; // sum에 더해주고 끝점 앞으로
}
if (sum==M) cnt++; // sum이 M과 같으면 경우의수 증가
}
System.out.println(cnt);
}
}
주의점
첫번째 방법은 시간복잡도가 O(N²)이고 투포인터의 경우 시간복잡도가 O(N)이다.
이 문제보다 범위가 커질경우 첫번째 방법으로는 통과하지 못할 수도 있다.
'공부 일지 > 문제풀이' 카테고리의 다른 글
| [프로그래머스] 동명 동물 수 찾기(MySQL) (0) | 2023.11.15 |
|---|---|
| [백준] 대표 선수 (JAVA) (0) | 2023.05.14 |
| [백준] 배열 돌리기 4 (JAVA) (0) | 2023.05.09 |
| [백준] 파이프 옮기기 (JAVA) (0) | 2023.05.09 |
| [백준] ⚾야구 (JAVA) (0) | 2023.05.03 |