투 포인터 알고리즘 (Two Pointer Algorithm)은
리스트에서 두 개의 포인터를 사용해 원하는 결과를 찾거나
특정 조건을 만족시키는 알고리즘이다.
보통 O(N)에 문제를 해결할 수 있어 유용하다!
두 포인터를 한 방향으로 진행: 두 포인터를 리스트의 시작 위치에서 같은 방향으로 움직인다.
일반적으로 시작 위치와 끝 위치에서 시작하고, 필요에 따라 포인터를 이동시키면서 조건을 만족하는 부분을 찾는다.
두 포인터를 반대 방향으로 진행: 두 포인터를 배열이나 리스트의 양 끝에서 서로 반대 방향으로 움직인다.
이 방식은 주로 두 요소의 합, 차 등을 비교하거나 반대 방향에서 수렴해가는 문제를 해결할 때 사용됩니다.
백준 1940번
https://www.acmicpc.net/problem/1940
1940번: 주몽
첫째 줄에는 재료의 개수 N(1 ≤ N ≤ 15,000)이 주어진다. 그리고 두 번째 줄에는 갑옷을 만드는데 필요한 수 M(1 ≤ M ≤ 10,000,000) 주어진다. 그리고 마지막으로 셋째 줄에는 N개의 재료들이 가진 고
www.acmicpc.net
import sys
input=sys.stdin.readline
N=int(input())
M=int(input())
gabot=input().split()
answer=0
pointer1=0
pointer2=0
for i in range(N):
pointer2=pointer1+1
while(N>pointer2>pointer1):
if int(gabot[pointer1])+int(gabot[pointer2])==M:
answer+=1
pointer2+=1
pointer1+=1
print(answer)
이 코드는 처음에 내가 짠 코드이다.
N<=2000일 때 N^2의 시간복잡도가 1초안에 풀리므로 N<=15000일때 N^2 알고리즘은 시간 초과가 날 수 밖에 없다.
따라서 다음의 코드로 고쳤다.
#입력 받기
import sys
input=sys.stdin.readline
N=int(input())
M=int(input())
#list에 int꼴로 저장하고 싶을 땐 이 코드가 가장 유용한 것 같다.
#cf) '1' 와 같은 문자형 숫자는 sort 시 아스키코드 크기 순으로 배열되므로
#0~9까지는 순서대로 배열되지만 10을 넘어가면 순서가 틀려진다!
gabot=list(map(int,input().split()))
answer=0
pointer1=0
pointer2=N-1
#리스트 sort해주기!
gabot.sort()
while(pointer2>pointer1):
if gabot[pointer1]+gabot[pointer2]<M:
pointer1+=1
elif gabot[pointer1]+gabot[pointer2]>M:
pointer2-=1
else:
answer+=1
pointer1+=1
pointer2-=1
print(answer)
바뀐 코드 중 가장 중요한 것은 sort를 했다는 점이다. 리스트 원소들의 합이 원하는 값인지 아닌지를 묻는 문제 이므로 각 원소들의 index는 바뀌어도 상관없다. 오름차순으로 정렬을 했기 때문에 포인터 두 개를 가지고 원하는 값을 찾아가게 된다.
백준 2018번
https://www.acmicpc.net/problem/2018
2018번: 수들의 합 5
어떠한 자연수 N은, 몇 개의 연속된 자연수의 합으로 나타낼 수 있다. 당신은 어떤 자연수 N(1 ≤ N ≤ 10,000,000)에 대해서, 이 N을 몇 개의 연속된 자연수의 합으로 나타내는 가지수를 알고 싶어한
www.acmicpc.net
N=int(input())
count=1
start_index=1
end_index=1
#본인 수 미리 세두기
sum=1
while end_index!=N:
if sum==N:
count+=1
end_index+=1
sum+=end_index
elif sum>N:
sum-=start_index
start_index+=1
else:
end_index+=1
sum+=end_index
print(count)
위의 주몽 문제를 푼 방법가 거의 유사하게 풀면 쉽게 풀어낼 수 있다. 이때 문제 조건과 예시를 보면 N을 나타내는 방법에 N 본인도 포함되기 때문에 sum=1로 시작한다.
백준 1253번
https://www.acmicpc.net/problem/1253
1253번: 좋다
첫째 줄에는 수의 개수 N(1 ≤ N ≤ 2,000), 두 번째 줄에는 i번째 수를 나타내는 Ai가 N개 주어진다. (|Ai| ≤ 1,000,000,000, Ai는 정수)
www.acmicpc.net
import sys
input=sys.stdin.readline
N=int(input())
num=list(map(int,input().split()))
num.sort()
answer=0
for i in range(N):
goodnum=num[i]
start=0
end=N-1
while(start<end):
#음수까지 리스트에 포함되어 있어 sort후 goodnum의 한쪽 편만 순회하는 것이 의미 없다
#따라서 end와 start는 goodnum을 넘어서도 리스트를 순회해야한다.
#end와 start가 goodnum을 가리키면 한칸 넘기고 다음 loop를 순회한다.
if start==i:
start+=1
continue
elif end==i:
end-=1
continue
if num[start] + num[end]==goodnum:
answer+=1
break
elif num[start] + num[end]>goodnum:
end-=1
else:
start+=1
print(answer)
이 문제는 goodnum을 넘어서 순회해야 하므로 continue를 쓴 부분이 중요하다.
'코딩 테스트 풀이' 카테고리의 다른 글
파이썬 알고리즘 공부 - 구간 합 (3) | 2023.08.29 |
---|---|
파이썬 알고리즘 시간복잡도 (0) | 2023.08.28 |
백준 2164번 파이썬 풀이 (0) | 2023.08.21 |