isPowerfulBlog

[Solved] BOJ: 11053 | 가장 긴 증가하는 부분 수열 본문

Algorithm

[Solved] BOJ: 11053 | 가장 긴 증가하는 부분 수열

왕밤빵도라에몽 2022. 11. 28. 19:26

문제

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하기

입력과 출력

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.
둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)

출력

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.


문제 해결 요약

  1. 수열의 길이를 카운트하는 dp 테이블 생성(카운트값)
  2. 전체 순열을 순회하면서 i번째 수에 대해
  3. i-1부터 첫번째 인덱스까지 역으로 순회하며
  4. i번째 수보다 크다면 해당 수의 카운트값+1로 i번째 카운트값을 갱신

코드 설명

import 및 입력받기

-

import sys
input = sys.stdin.readline

n = int(input())
seq = [0]
seq += list(map(int, input().split()))
  • 수열의 길이 n과 수열 seq를 입력받음
  • 인덱싱 편의를 위해 seq 리스트 맨 처음에 0을 추가하여 인덱스를 1부터 셀 수 있도록 함

dp 테이블 생성

각 수에 대해 카운트값을 저장할 dp 테이블 생성

-

cnt = [0] + [1 for _ in range(n)]
  • seq와 인덱스를 맞춰주기 위해 cnt 리스트도 0을 맨 앞에 추가
  • 어떤 수이든 기본적으로 cnt값이 최소 1은 되므로 1로 초기화

dp테이블에 카운트값 갱신

수열 전체를 순회,
i번째보다 인덱스가 작은 부분들의 cnt값을 체크하여
i번쨰 cnt값을 갱신

-

for i in range(2, n+1):
    j = i-1
    while j > 0:
        if seq[i] > seq[j]:
            cnt[i] = max(cnt[j]+1, cnt[i])
            j -= 1
        else:
            j -= 1
  • 수열의 제일 첫번째 수는 무조건 카운트 값이 1 이므로 1부터 순회할 필요 없음 -> 2부터 순회
  • 아까 인덱싱 편의를 위해 리스트 앞에 의미없는 0을 추가했으므로 n+1 전까지 순회
  • i보다 인덱스가 작은 부분들을 역으로 순회하면서
  • cnt값 + 1이 i번째 cnt값보다 크다면
  • i번째 cnt 값을 갱신

dp 테이블의 최댓값 출력

print(max(cnt))
  • dp 테이블에서 max값을 출력하는게 답

전체 코드

import sys
input = sys.stdin.readline

n = int(input())
seq = [0]
seq += list(map(int, input().split()))
cnt = [0] + [1 for _ in range(n)]

for i in range(2, n+1):
    j = i-1
    while j > 0:
        if seq[i] > seq[j]:
            cnt[i] = max(cnt[j]+1, cnt[i])
            j -= 1
        else:
            j -= 1

print(max(cnt))
  • 근데 사실 j 돌릴때 역으로 안 하고 1부터 i보다 작을 때까지 while문 돌려도 됨, 역으로 하면 갱신 횟수가 좀 더 적을 듯

image