Home [알고리즘] 알아야 빨리푼다, LIS 알고리즘
Post
Cancel

[알고리즘] 알아야 빨리푼다, LIS 알고리즘

최장 증가 부분수열 (Longest Increasing Subsequence)

: 주어진 수열에서 만들 수 있는 오름차순을 만족하는 가장 긴 부분수열을 뜻한다.

1
2
3
ex) 
[3, 2, 4, 1, 5]의 LIS는 [2, 4, 5]
[5, 3, 4, 1, 6, 8, 9]의 LIS는 [3, 4, 6, 8, 9]

LIS문제는 dp(Dynamic Programming)기법으로 해결할 수 있다.

수열이 주어졌다면 수열과 같은 길이를 같는 배열을 만들어주자.

1
2
arr = [5, 3, 4, 1, 6, 10, 8, 9]
dp = [0] * len(arr)

dp 배열은 해당 위치까지 만들 수 있는 LIS를 저장해준다.
dp[i]를 갱신해줄 때는 두가지 조건을 갖추어야 한다.

  1. arr[j] < arr[i]: 오름차순을 만족하기 위함
  2. len(dp[j]) + 1 > len(dp[i]): 순회하면서 조회중인 dp[j]의 길이에 나 자신을 포함한 값이 현재 dp[i]의 길이보다 길어야 한다.
1
2
3
4
5
for i in range(len(arr)):
    dp[i] = [arr[i]]
    for j in range(0, i):
        if (arr[i] > arr[j]) and ((len(dp[j]) + 1) > len(dp[i])):
            dp[i] = dp[j] + [arr[i]]

모든 dp를 갱신해준뒤 출력해보면 아래와 같이 해당 위치까지에서 찾을 수 있는 lis를 저장한 것을 확인할 수 있으며 가장 긴 길이를 가진 [3, 4, 6, 8, 9]를 잘 찾아낸 것을 확인할 수 있다.

1
2
print(dp)
# [[5], [3], [3, 4], [1], [3, 4, 6], [3, 4, 6, 10], [3, 4, 6, 8], [3, 4, 6, 8, 9]]

LIS 알고리즘으로 풀 수 있는 문제

백준 2631번: 줄세우기

이 문제는 N명의 학생들이 1~n까지의 번호표를 달고 무작위 순서로 줄을 서있을 때 최소한의 횟수로 학생들을 옮겨 번호 순서대로(오름차순) 다시 줄을 세워야 하는 문제이다.
이 문제를 LIS알고리즘을 활용해 해결할 수 있는데 최소한의 횟수만큼만 움직여야 하니까 주어진 배열에서 LIS를 구하면 올바른 위치에 서있는 학생의 수를 구할 수 있게 되고, 그 외의 학생들을 올바른 위치로 옮겨주면 올바르게 줄을 세울 수 있다. 간단히 식으로 구하면 아래와 같다.

1
최소한의 횟수 = (학생들의 수) - (현재 배열에서 구한 LIS의 길이)

식에서 우리가 알고 있는 것은 학생들의 수이므로 구어진 배열에서 LIS의 길이만 구하면 된다. 이 글에서 소개한 방법으로는 LIS자체를 구했는데 조금만 수정해주면 쉽게 LIS의 길이를 구할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import sys

input = sys.stdin.readline
n = int(input())

arr = []
dp = []
maxValue = 0
for _ in range(n):
    arr.append(int(input()))
    dp.append(0)


for i in range(n):
    dp[i] = 1
    for j in range(0, i):
        if arr[i] > arr[j] and dp[j] + 1 > dp[i]:
            dp[i] = dp[j] + 1
    
    if dp[i] > maxValue:
        maxValue = dp[i]
print(n-maxValue)
This post is licensed under CC BY 4.0 by the author.

오랜만에 올리는 글.. 내 근황..

[Setting] M1 pro 맥북 개발환경 세팅.기록