[Algorithm] 투 포인터 알고리즘

조재훈·2025년 5월 28일

투 포인터 알고리즘

투 포인터 알고리즘이란?
두 개의 포인터를 이용해 배열이나 문자열을 탐색하며 문제를 해결하는 알고리즘

보통 일차원 자료구조에서 특정 조건을 만족하는 연속 구간을 구할 때 O(N)의 시간 복잡도로 문제를 해결하기 위해 많이 사용되는 기법이며 코딩 테스트에서도 자주 등장하는 알고리즘이다

보통 이중루프로 풀어야 할 것 같은데 입력값이 커서 시간 초과가 날 것 같을 때 투 포인터 알고리즘을 떠올리면 대부분 풀어지더라

이와 비슷한 알고리즘 기법인 슬라이딩 윈도우도 있는 데 차이는 투 포인터는 구간이 가변적이며 슬라이딩 윈도우는 구간이 고정적이다. 자세한 건 다음 포스팅에서 다뤄보자


대부분 투 포인터 알고리즘은 인덱스를 나타내는 포인터인 leftright를 사용하며 문제의 유형은 다음과 같다

  • 포인터 2개가 같은 방향으로 진행
  • 포인터 2개가 양 끝에서 시작해 서로를 향해 다가오며 진행
  • 포인터 하나는 단방향으로 진행하고, 다른 포인터는 양쪽으로 이동

백준 2003번 : 수들의 합 2

간단하고 대표적인 투 포인터 문제이다

시간 제한이 0.5초이고 배열의 길이는 10000까지이며 구간 [i, j] 내의 값들의 합이 M이 되는 경우를 찾아야 한다

만약 투 포인터를 안 쓸 경우 이중루프를 통해 구해야 되는데 바로 시간 초과가 뜬다

코드

#include <bits/stdc++.h>

using namespace std;

int N, M;
int arr[10004];
int answer;

void Input() 
{
	cin >> N >> M;

	for (int i = 0; i < N; i++)
	{
		cin >> arr[i];
	}
}

void Solve()
{
	int left = 0, right = 0;
	int sum = arr[0];

	while (right < N)
	{
		if (sum == M)
		{
			answer++;
			sum += arr[++right];
		}
		else if(sum > M)
		{
			sum -= arr[left++];
		}
		else if (sum < M)
		{
			sum += arr[++right];
		}
	}

	cout << answer;
}

int main() 
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	Input();
	Solve();

	return 0;
}

풀이

이 문제의 경우 left와 right 포인터를 이용해 구간의 합을 구해가며 경우의 수를 구하는 문제이다

left와 right가 배열의 0번째 인덱스에서 같이 시작하는 것이 포인트

sum 변수는 [left, right]의 구간 합으로 생각하면 된다. 그러니까 0번째 인덱스의 변수로 초기화시켰다

루프 본문부터 살펴보면 현재 구간합이 M과 같다면 경우의 수를 증가시키고 right + 1 인덱스의 값을 sum에 더해준다. 그러니까 현재 구간을 [left, right + 1]로 바꾸는 것임

만약 M보다 크다면 현재 sum에서 left 인덱스 값을 빼준다. 구간을 [left + 1, right]로 변경하는 것

M보다 작다면 그냥 right를 한 칸 더 옮겨준다

여기서 내가 헷갈렸던 부분은 보통 left가 right보다 커지면 문제가 발생하는 것 같았는데 투 포인터의 경우 보통 이 조건이 추가되면 틀렸다

5 2
5 5 5 1 1

라는 입력이 들어온다고 생각해보자

위처럼 구현한다하면 처음부터 sum이 M을 넘겼기에 left가 right보다 커진다. 그러면 루프가 종료되어버려 답을 구할 수 없다

투 포인터에서의 핵심은 조건을 잘 정해주고 머릿속으로 시뮬레이션을 잘 해야 할 것 같다

profile
나태지옥

0개의 댓글