정석 풀이가 아닐 수 있습니다.
팰린드롬 : '회문'과 같은 말로, 뒤집어도 처음과 똑같은 수열을 가리키는 말이다.
1 2 3 4 2
에 최소의 숫자를 추가해서 팰린드롬을 만드는 문제이다.
이 경우 4와 2 사이에 3을, 2 다음에 1을 추가하여 1 2 3 4 3 2 1
을 만들 수 있다. (추가한 숫자 2개)
DP[i][j]
는 i번째 글자부터 j번째 글자까지를 팰린드롬으로 만들기 위해 끼워넣어야 하는 수의 개수이다.DP[3][4]
는 4 2
를 팰린드롬으로 만들기 위해 필요한 수이며, 이 경우 오른쪽 끝에 2를 끼워넣거나, 왼쪽 끝에 2를 끼워 넣어 1임을 알 수 있다.DP[i][i+1]
의 값은 1이된다.DP[2][4]
를 마주하였을 때의 경우이다.DP[i][j-1]
과 DP[i+1][j]
값의 최소값을 구하여 여기에 1을 더한 숫자가 DP[i][j]
의 값이 된다.DP[2][4]
는 DP[2][3], DP[4]
또는 DP[2], DP[3][4]
로 쪼개어 생각할 수 있다.2 3 2
또는 3 4 3
)DP[2][4]
는 팰린드롬의 한쪽 끝에 숫자 하나를 추가한 꼴이 된다. (2 3 2 4
또는 2 3 4 3
) DP[i][j-1]
과 DP[i+1][j]
중 최소값을 취하여 1을 더하면 DP[i][j]
의 값이 된다.DP[i][j]
에서 arr[i]==arr[j]
인 경우이다.DP[i+1][j-1]
의 값이 그대로 DP[i][j]
값이 된다.DP[i+1][j-1]
이 알고 있으므로 그냥 값을 가져오면 된다.DP[0][-1]
을 구했다면, 이것이 전체 수열을 팰린드롬으로 만들기 위해 추가해야할 수이다.풀이는 (N, N) 크기 이차원 행렬로 했지만 사실 (2, N) 크기의 행렬만 있어도 가능하다.
그 이유는 어짜피 정답은 DP[0][-1]
으로 고정되어 있고, 한번에 봐야하는 행이 i와 i+1 2개이기 때문이다.
import sys
input = sys.stdin.readline
N = int(input())
arr = list(map(int, input().split()))
dp = [[0] * N for _ in range(2)]
# 뒷부분부터 탐색해야함
for i in reversed(range(N)):
for j in range(i+1, N):
# 짝수와 홀수 구분
row = i % 2
# 홀수행(i=1)일 때 i-1=0으로 짝수행을 가리킴, 짝수행(i=0)일 때 i-1=-1로 홀수행을 가리킴
if arr[i] == arr[j]:
dp[row][j] = dp[row-1][j-1]
else:
dp[row][j] = min(dp[row][j-1], dp[row-1][j]) + 1