일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 반효경교수님
- lcap
- git
- microflow
- 알고리즘
- 정렬
- 프로그래머스
- 가중치없는그래프
- 해시맵
- MySQL
- 자료구조
- 자바
- 매개변수 탐색
- 이분탐색
- 완전탐색
- 그래프
- 멘딕스
- Bruteforce
- 스택
- 백트래킹
- 트리
- Recursion
- algorithm
- SQL
- Mendix
- 재귀
- dfs
- Sort
- domain model
- 집합
- Today
- Total
mondegreen
[240321] 알고리즘 리부트 35일차 - 백준 2003, 1806 자바 본문
[240321] 알고리즘 리부트 35일차 - 백준 2003, 1806 자바
앙갱 2024. 3. 21. 22:51[Part1-Chapter08-Clip01]
- 백준 2003 수들의 합2
투 포인터란 선형 데이터 구조에서 두 개의 인덱스를 관리하여 특정 조건을 만족하는 부분집합이나 특정 값을 찾는 알고리즘을 말한다. 포인터를 사용하는 방식은 다음과 같이 다양할 수 있다. 1) 같은 배열에서 동일한 방향으로 이동하는 투포인터 (이 경우 2003 문제이다.) 2) 같은 배열에서 마주보는 방향으로 이동하는 투포인터 3) 서로 다른 배열에서 이동하는 투포인터. 이때 두 포인터 중 경우에 따라 하나 또는 모두가 끝에 도달할 때까지 반복한다.
아래는 부분합 배열을 구현하여 풀이한 것이다. l과 r을 시작 원소와 끝 원소의 인덱스로 지정하고 해당 구간의 부분합이 m과 비교하여 큰지 작은지 같은지에 따라 포인터를 움직임으로써 경우의 수를 셀 수 있게 구현하였다.
package BaekJoon.twopointer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class BJ2003 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
int[] arr = new int[n + 1];
int[] acc = new int[n + 1];
st = new StringTokenizer(br.readLine());
for (int i = 1; i <= n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
//System.out.println(Arrays.toString(arr));
acc[1] = arr[1];
for (int i = 2; i <= n; i++) {
acc[i] = acc[i - 1] + arr[i];
}
//System.out.println(Arrays.toString(acc));
int cnt = 0;
int l = 1;
int r = 1;
while (l <= n && r <= n) {
//System.out.printf("l은 %d, r은 %d", l, r);
//System.out.println();
if (acc[r] - acc[l - 1] == m) {
r++;
cnt++;
//System.out.println("더해졌어요");
} else if (acc[r] - acc[l - 1] > m) l++; // 구간을 좁혀야 합이 줄어들기 때문
else r++;
}
System.out.println(cnt);
}
}
아래 코드는 강의에서 다룬 코드이다. 부분합을 구하지 않더라도 투포인터만으로 문제를 풀 수 있다. i를 기준으로 오른쪽 인덱스 변수를 별도로 두고 탐색을 시작한다. i는 시작지점이고 r을 움직여가면서 만약 m보다 크거나 같다면 반복문을 빠져나온다. 만약 m보다 큰 경우 현재 시작점에서부터 오른쪽 인덱스의 원소까지 더하면 m과 일치하는 합을 구할 수 없기 때문에 그 때는 시작점의 원소 값을 합에서 빼고 시작점을 움직여서 판별을 다시 시작한다.
package BaekJoon.twopointer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class BJ2003_1 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
int[] arr = new int[n + 1];
st = new StringTokenizer(br.readLine());
for (int i = 1; i <= n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
//System.out.println(Arrays.toString(arr));
int cnt = 0;
int rightIdx = 1;
int currentSum = arr[1];
// 여기서는 시간 복잡도가 n^2이 아니다. 전체 배열을 보는 게 아니라 경계값만 보고 있음 O(n)임
for (int i = 1; i <= n; i++) {
while (currentSum < m && rightIdx < n) {
currentSum += arr[++rightIdx];
}
if (currentSum == m) cnt++;
// 만약 현재까지 더한 값이 m과 같은 게 아니라 컸다면 이 시작점에서는 m을 만들 구간이 없다는 것을 의미하니까
// 시작점의 값을 뺀 기존의 합인 값이 m과 비교해서 작은지 큰지 또 비교한다.
currentSum -= arr[i];
}
System.out.println(cnt);
}
}
[Part1-Chapter08-Clip02]
- 백준 1806 부분합
수들의 합 2 문제와 비슷한데 같을 때 뿐만 아니라 초과하는 경우도 찾아야 하고 구간의 길이가 가장 짧은 경우를 그 때 그 때 기록해뒀다가 최솟값으로 갱신해가며 반환하는 문제이다.
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int s = Integer.parseInt(st.nextToken());
int[] arr = new int[n];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
int minLen = Integer.MAX_VALUE;
int rightIdx = 0;
int tmpSum = arr[0];
for (int i = 0; i < n; i++) {
//System.out.println("현재 i: " + i);
while (tmpSum < s && rightIdx < n - 1) {
tmpSum += arr[++rightIdx];
//System.out.println("현재 tmpSum: " + tmpSum);
}
if (tmpSum >= s) {
minLen = Math.min(minLen, rightIdx - i + 1);
//System.out.println("현재 minLen: " + minLen);
}
tmpSum -= arr[i];
//System.out.println("현재 값 뺐어요");
}
System.out.println(minLen == Integer.MAX_VALUE ? 0 : minLen);
}
}
'알고리즘 풀이 및 리뷰 > [패캠] 핵심유형 20개로 한 번에 끝내는 알고리즘 코딩테스트 리뷰' 카테고리의 다른 글
[240325] 알고리즘 리부트 38일차 - 백준 10828 자바 (0) | 2024.03.25 |
---|---|
[240322] 알고리즘 리부트 36일차 - 백준 2230 자바 (0) | 2024.03.22 |
[240320] 알고리즘 리부트 34일차 - 백준 1406 자바 (0) | 2024.03.20 |
[240318] 알고리즘 리부트 32일차 - 백준 2110 자바 (1) | 2024.03.18 |
[240314] 알고리즘 리부트 31일차 - 백준 6236 자바 (0) | 2024.03.14 |