Two Pointer(투 포인터)

Apr 21, 2019


출처 : https://www.codeground.org/common/popCodegroundNote#

투 포인터(Two Pointer) 알고리즘은 연속된 값들을 이용하여 풀어나가는 문제에 한정적으로 사용해야 하지만 매우 효율적인 알고리즘입니다.

직관적으로 보았을 때 O(N^2)이상으로 해결해야하는 문제를 선형시간(O(N))으로 해결해주기 때문입니다.

예를 들면, 1. 정렬된 두 배열이 주어질 때 두 배열을 하나의 정렬된 배열로 합치는 경우,

2 . 어떤 배열의 연속 부분집합(contiguous subrarray)의 원소의 합이 k인 경우의 수를 찾는 경우 등이 있습니다.

투 포인터 알고리즘의 기본 동작원리는 이름 그대로 두 개의 지점(포인터)를 옮겨가면서 구하고자 하는 답을 구하는 것입니다.

1번에서 두 배열을 이어 정렬한다면 O((N+M)log(N+M))에 해결할 수 있지만,

투 포인터를 사용할 경우 A배열의 포인터가 한번 순회, B배열의 포인터가 한번 순회로 총 O(N+M)이 나오므로 효율적입니다.

2번에서 투 포인터를 사용하면

SUM[L,R] < k 일 때, R을 증가시켜주어 k에 근접할 수 있도록 범위를 넓혀주며
SUM[L,R] > k 일 때, L을 증가시켜주어 범위를 좁혀주며
SUM[L,R] == k 일 때는 정답을 카운트해주며 다음 경우를 찾기 위해 다시 L을 증가시켜주어 범위를 좁혀줍니다.
이 알고리즘 또한 두 포인터가 하나의 배열을 두 번 탐색하는 것과 같으므로 시간복잡도는 O(N)으로 빠르게 동작합니다.

특수한 상황에서만 적용 가능한 알고리즘이지만, 동작속도가 빠르므로 유용하게 쓰입니다.

1번. 정렬된 두 배열을 합칠 때 코드

입력
첫 번째 줄에 배열 A의 원소의 개수가 주어지고
두 번째 줄에 배열 A의 원소가 주어진다.
세 번째 줄에 배열 B의 원소의 개수가 주어지고
네 번째 줄에 배열 B의 원소가 주어진다.
배열 A, B는 모두 오름차순으로 정렬되어있다.

Sample Input 4
1 2 8 9
5
-3 3 4 5 11

출력
A, B 두 배열을 합친 후 원소들을 정렬하여 출력한다.

Sample Output
-3 1 2 3 4 5 8 9 11

#include <iostream>
#define MAX 5005
int A[MAX], B[MAX];
int Sorted[MAX + MAX];
int main() {
    int n, m;
    scanf_s("%d", &n);
    for (int i = 0; i < n; i++)
        scanf_s("%d", &A[i]);
    scanf_s("%d", &m);
    for (int i = 0; i < m; i++)
        scanf_s("%d", &B[i]);

    int a = 0, b = 0;//a와 b의 위치

    for (int i = 0; i < n + m; i++) {//★★★★★
        if (b == m || (b != m && a < n && A[a] < B[b]))
            Sorted[i] = A[a++];
        else
            Sorted[i] = B[b++];
    }

    for (int i = 0; i < n + m; i++)
        printf("%d ", Sorted[i]);
}