투 포인터/슬라이딩 윈도우

2023. 11. 1. 22:59·Algorithm/알고리즘 이론
목차
  1. 투 포인터
  2. 슬라이딩 윈도우

투 포인터

2개의 포인터로 알고리즘의 시간 복잡도를 최적화함
 
 
[문제 006] 연속된 자연수의 합 구하기
N의 최댓값이 10,000,000으로 매우 크므로 O(nlogn)의 시간 복잡도 알고리즘을 사용하면 제한 시간을 초과하므로 O(n) 시간 복잡도 알고리즘을 사용해야 함
⇒ 이런 경우 자주 사용하는 방법이 투 포인터
 
💡 투 포인터 이동 법칙

  1. sum > N: sum = sum-start_index; start_index++;
  2. sum < N: end_index++; sum = sum+end_index;
  3. sum = N: end_index++; sum = sum+end_index; count++;
  • start_index를 오른쪽으로 한 칸 이동하는 것은 연속된 자연수에서 왼쪽 값을 삭제하는 것
  • end_index를 오른쪽으로 한 칸 이동하는 것은 연속된 자연수의 범위를 한 칸 더 확장하는 것
  • sum이 N과 같을 때는 경우의 수를 +1 하고, end_index를 오른쪽으로 이동시킴
n = int(input())

left, right = 0, 0 # 투 포인터
sum = 0 # left ~ right 까지의 합
answer = 0 # 가짓수

# right가 n이 될 때까지 반복
while right <= n:
    # 합이 n이면
    if sum == n:
        answer += 1 # 가짓수 +1
        right += 1
        sum += right
    # 합이 n보다 작으면 right 포인터 오른쪽으로 한 칸 이동
    elif sum < n:
        right += 1
        sum += right
    # 합이 n보다 크면 left 포인터 오른쪽으로 한 칸 이동
    elif sum > n:
        sum -= left
        left += 1

print(answer)

 
[문제 007] 주몽의 명령
N의 최대 범위가 15,000이므로 O(nlogn) 시간 복잡도 알고리즘을 사용해도 문제없음

  • 일반적으로 정렬 알고리즘의 시간 복잡도는 O(nlogn)이므로 정렬 사용 가능
  • N개의 재료값을 오름차순 정렬한 다음 양쪽 끝의 위치를 투 포인터로 지정해 접근

💡 투 포인터 이동 원칙

  1. A[i] + A[j] > M: j—;
  2. A[i] + A[j] < M: i++;
  3. A[i] + A[j] = M: i++, j—; count++;
n = int(input()) # 재료의 개수
m = int(input()) # 갑옷을 만드는데 필요한 두 재료의 합
nlist = list(map(int, input().split())) # n개의 재료 고유 번호

left, right = 0, n-1 # 시작 인덱스, 끝 인덱스 
answer = 0 # 경우의 수

nlist.sort() # nlist를 정렬해준 후 투 포인터로 접근

# left와 right가 만날 때까지 반복
while left < right:
    # 두 재료의 합이 m이면
    if nlist[left] + nlist[right] == m:
        answer += 1
        left += 1
        right -= 1
    # 두 재료의 합이 m보다 작으면 left +1
    elif nlist[left] + nlist[right] < m:
        left += 1
    # 두 재료의 합이 m보다 크면 right -1
    elif nlist[left] + nlist[right] > m:
        right -= 1

print(answer)

 
[문제 008] ‘좋은 수’ 구하기
💡 투 포인터 이동 원칙

  1. A[i] + A[j] > K: j—;
  2. A[i] + A[j] < K: i++;
  3. A[i] + A[j] = K: count++; 프로세스 종료
n = int(input()) # 수의 개수
nlist = list(map(int, input().split())) # n개의 수

answer = 0 # 경우의 수

nlist.sort()

for i in range(n):
    temp = nlist[:i] + nlist[i+1:] # i를 제외한 리스트
    start, end = 0, len(temp)-1

    while start < end:
        # 두 수의 합이 nlist[i]이면 경우의 수 +1
        if temp[start] + temp[end] == nlist[i]:
            answer += 1
            break
        # 두 수의 합이 nlist[i]보다 작으면 start +1
        elif temp[start] + temp[end] < nlist[i]:
            start += 1
        # 두 수의 합이 nlsit[i]보다 크면 end -1
        else:
            end -= 1

print(answer)

 
 

슬라이딩 윈도우

2개의 포인터로 범위를 지정한 다음, 범위(window)를 유지한 채로 이동(sliding)하며 문제를 해결하는 방식
 
 
[문제 009] DNA 비밀번호

s, p = map(int, input().split()) # DNA 문자열 길이, 비밀번호 부분 문자열 길이
dna = input() # DNA 문자열
a, c, g, t = map(int, input().split()) # 'A', 'C', 'G', 'T'의 최소 개수
password = 0 # 만들 수 있는 비밀번호의 개수

count = {'A': 0, 'C': 0, 'G': 0, 'T': 0}

for i in range(s-p+1):
    # 초기 길이 p의 문자열의 acgt 개수 파악
    if i == 0:
        for j in range(p):
            count[dna[j]] += 1
    # 한 칸 씩 이동하며 왼쪽 값 -1(제거), 오른쪽 값 +1(추가)
    else:
        count[dna[i-1]] -= 1
        count[dna[i-1+p]] += 1

    # 조건에 맞는 지 확인 후 개수 +1
    if count['A'] >= a and count['C'] >= c and count['G'] >= g and count['T'] >= t:
        password += 1

print(password)

 
[문제 010] 최솟값 찾기 1
💡 deque의 구조

from collections import deque

N, L = map(int, input().split())
A = list(map(int, input().split())) # n개의 수

queue = deque()
for i in range(N):
    # 가장 마지막 원소의 값이 A[i]보다 크면 queue에서 제거
    while queue and queue[-1][1] > A[i]:
        queue.pop()
    
    queue.append((i, A[i])) # (인덱스, 값) 형식으로 queue에 추가

    # 범위 L을 벗어나면 맨 앞에 위치한 원소 queue에서 제거
    if queue[-1][0] - queue[0][0] >= L:
        queue.popleft()

    print(queue[0][1], end=' ') # 공백으로 구분하여 출력

 
 

참고: Do it 알고리즘 코딩테스트: 파이썬 편

 
저작자표시 (새창열림)
  1. 투 포인터
  2. 슬라이딩 윈도우
'Algorithm/알고리즘 이론' 카테고리의 다른 글
  • 정렬
  • 스택(Stack)/큐(Queue)/우선순위 큐(Priority Queue)/힙(Heap)
  • 구간 합
  • 배열과 리스트
dduniverse
dduniverse
  • dduniverse
    dduniverse
    dduniverse
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • Algorithm (123)
        • 알고리즘 이론 (8)
        • 백준 (19)
        • 프로그래머스 (83)
        • 구름 알고리즘 먼데이 챌린지 (13)
      • 빅데이터분석기사 (10)
        • 통계 (4)
        • 실기 (6)
      • KT에이블스쿨 (26)
      • FrontEnd (11)
        • React (5)
        • 기타 (6)
      • BackEnd (18)
        • Django (15)
        • Spring (3)
      • DS & ML (11)
        • Machine Learning (9)
        • Kaggle (2)
      • TIL (44)
        • python (22)
        • javascript (3)
        • 오류해결 (10)
        • 기타 (8)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 관리
    • 글쓰기
  • 링크

  • 인기 글

  • hELLO· Designed By정상우.v4.10.0
dduniverse
투 포인터/슬라이딩 윈도우

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.