그리디 알고리즘
위의 과정을 수열이 끝날때까지 반복함
수열 A, B의 공통 수열 중 사전 순으로 가장 나중인 수열은 공통 수열에 들어갈 수 있는 수 중 최댓값으로 시작함
따라서 두 수열에서 공통 수열에 들어갈 수 있는 최댓값을 수열의 앞에서부터 찾아야 함
최댓값을 찾았다면 수열 A, B를 각각 찾은 최댓값까지의 수열과 그 뒤의 수열로 나눌 수 있음
만약 최댓값까지의 수열 중 공통 수열에 들어갈 수 있는 값을 뽑는 순간 최댓값보다 작은 값이 들어가기 때문에 사전 순으로 앞으로 갈 수밖에 없음
그러므로 나눈 수열의 앞은 확인할 필요가 없어짐
이제 뒤의 수열을 확인해야 하는데 여기서도 똑같이 사전 순으로 나중이 되는 값을 찾으려면 공통 수열에 들어갈 수 있는 최댓값을 찾으면 됨
그렇게 수열을 나눠보면서 공통 수열이 될 수 있는 최댓값들을 찾아내면 답
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.StringTokenizer
fun main(args: Array<String>) {
val br = BufferedReader(InputStreamReader(System.`in`))
val N = br.readLine().toInt()
var st = StringTokenizer(br.readLine())
val A = IntArray(N + 1)
for(i in 1..N){
A[i] = st.nextToken().toInt()
}
val M = br.readLine().toInt()
st = StringTokenizer(br.readLine())
val B = IntArray(M + 1)
for(i in 1..M){
B[i] = st.nextToken().toInt()
}
//공통 부분 수열중 사전 순으로 가장 나중인 수열이 LCS의 부분 수열이 아닐 수 있음
//부분 수열이 될 수 있는 수 중 가장 큰 값을 찾아서 그 값을 답에 저장하고
//각 수열에서 그 뒤에 부분에서 다시 부분 수열이 될 수 있는 수중 가장 큰 값 찾기
var idxA = 1
var idxB = 1
var answer = ArrayList<Int>()
while(idxA <= N && idxB <= M){
var max = 0
var maxIdxA = 0
var maxIdxB = 0
for(i in idxA..N){
for(j in idxB..M){
if(A[i] == B[j] && A[i] > max){
max = A[i]
maxIdxA = i
maxIdxB = j
}
}
}
if(max > 0){
answer.add(max)
idxA = maxIdxA+1
idxB = maxIdxB+1
} else {
break
}
}
println(answer.size)
for(num in answer){
print("$num ")
}
}