투 포인터(Two Pointer)
- 배열 또는 리스트에서 두개의 포인터의 위치를 기록해가면서 원하는 결과를 찾아내는 알고리즘 (2가지 방법존재)
- 시작할 때, 정렬된 배열에서 처음 인덱스와 마지막인덱스를 두 개의 포인터가 가리키는 경우
- 시작할 때, 처음 인덱스를 두 개의 포인터가 모두 가리키는 경우
- 시간복잡도는 O(n)이다. (부분 배열을 이용해 탐색하기 때문에 O(n))
- 보통 선형 공간 탐색시 시간복잡도가 O(n²)이상이 되는 부분을 O(n)으로 줄이기 위해 사용된다.
- 이를 저격하는 문제는 투 포인터를 사용하지 않으면 시간초과가 발생한다.
두 포인터를 사용한 풀이에 대한 자세한 설명은 아래 글에 작성해두었다.
N이 되는 연속된 자연수의 합 - 처음 인덱스를 두 개의 포인터가 모두 가리키는 경우
[백준] 2018번 수들의 합 5 - JAVA(자바)
https://www.acmicpc.net/problem/2018 2018번: 수들의 합 5 어떠한 자연수 N은, 몇 개의 연속된 자연수의 합으로 나타낼 수 있다. 당신은 어떤 자연수 N(1 ≤ N ≤ 10,000,000)에 대해서, 이 N을 몇 개의 연속된 자
chobo24.tistory.com
[작성한 코드]
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int count=1; //가짓수 1개는 자기자신을 의미
//투포인터 풀이
int start = 0; //시작 포인터
int end = 0; //종료 포인터
int sum=0;
while(end<N) {
//sum이 더 크다면 시작포인터 증가
if(sum>N) {
//합의 시작 부분이 바뀌었기 때문에 원래 시작한 수는 빼줌
sum-=start;
start++;
}
//sum이 작다면 종료포인터 증가
else if(sum<N){
end++;
//연속된 합의 마지막 수 새로 더함
sum+=end;
}
else { //sum==N이라면
count++;
end++;
sum+=end;
}
}
System.out.println(count);
}
}
두 개의 수가 M이 되는 경우 - 정렬된 배열에서 처음 인덱스와 마지막인덱스를 두 개의 포인터가 가리키는 경우
[백준] 1940번 주몽 - JAVA(자바)
https://www.acmicpc.net/problem/1940 1940번: 주몽 첫째 줄에는 재료의 개수 N(1 ≤ N ≤ 15,000)이 주어진다. 그리고 두 번째 줄에는 갑옷을 만드는데 필요한 수 M(1 ≤ M ≤ 10,000,000) 주어진다. 그리고 마지막으
chobo24.tistory.com
[작성한 코드]
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));
int N = Integer.parseInt(br.readLine());
int M = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
int[] arr = new int[N];
//재료들 고유 번호 저장
for(int i=0; i<N; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
Arrays.sort(arr);
int start = 0; //시작포인터 - 작은 값 인덱스
int end = N-1; //종료포인터 - 큰 값 인덱스
int count = 0;
while(start<end) { //양쪽 포인터가 좁혀지다가 같아지기전까지 반복
int sum = arr[start]+arr[end];
if(sum>M) { //sum이 크다면 종료포인터를 왼쪽으로 이동
end--;
}
else if(sum<M) { //sum이 작다면 시작포인터를 오른쪽으로 이동
start++;
}
else { //sum==M이면 count증가 시작포인터와 종료포인터 모두 이동
count++;
end--;
start++;
}
}
System.out.println(count);
}
}
다른 두 수의 합으로 표현되는 수 찾기 - 정렬된 배열에서 처음 인덱스와 마지막인덱스를 두 개의 포인터가 가리키는 경우
[백준] 1253번 좋다 - JAVA(자바)
https://www.acmicpc.net/problem/1253 1253번: 좋다 첫째 줄에는 수의 개수 N(1 ≤ N ≤ 2,000), 두 번째 줄에는 i번째 수를 나타내는 Ai가 N개 주어진다. (|Ai| ≤ 1,000,000,000, Ai는 정수) www.acmicpc.net N개의 수 중 어
chobo24.tistory.com
[작성한 코드]
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));
int N = Integer.parseInt(br.readLine());
long[] arr = new long[N];
int count = 0; //좋다에 해당하는 수 개수
StringTokenizer st = new StringTokenizer(br.readLine());
//N개의 수 입력받아 저장
for(int i=0; i<N; i++) {
arr[i] = Long.parseLong(st.nextToken());
}
//투 포인터 사용을 위해 오름차순 정렬
Arrays.sort(arr);
for(int i=0; i<N; i++) {
int left = 0; //왼쪽포인터 - 작은 값 인덱스
int right = N-1; //오른쪽포인터 - 큰 값 인덱스
while(left<right) { //양쪽 포인터가 좁혀지다가 같아지기전까지 반복
long num = arr[left]+arr[right];
//num이 크다면 right포인터를 왼쪽으로 이동
if(num>arr[i]) right--;
//num이 작다면 left포인터 오른쪽으로 이동
else if(num<arr[i]) left++;
else { //num==arr[i]이면
if(left==i) left++; // left와 같다면 오른쪽으로 이동
else if(right==i) right--; //right과 같다면 왼쪽으로 이동
//자기자신을 제외하고 다른 두수의 합일 때, 좋다(GOOD)인 수로 판정 - 반복문 종료
else{
count++;
break;
}
}
}
}
System.out.println(count);
}
}
'Algorithm & Data Structure' 카테고리의 다른 글
[자료구조] 스택(Stack) - JAVA(자바) (0) | 2023.01.30 |
---|---|
[자료구조] 덱(Deque) - JAVA(자바) (0) | 2023.01.30 |
[알고리즘] 합병정렬(Merge Sort) - JAVA (0) | 2023.01.27 |
[알고리즘] 삽입정렬(insertion Sort) - JAVA(자바) (0) | 2023.01.25 |
[알고리즘] 선택정렬(Selection Sort) - Java(자바) (0) | 2023.01.24 |
댓글