치춘짱베리굿나이스
[백준] 9251 본문
LCS
문제
LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다.
예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.
입력
첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.
출력
첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를 출력한다.
풀이
#include <iostream>
#include <string>
#include <algorithm>
int arr[1002][1002] = {0};
void printArr(int aLen, int bLen) {
for (int i = 0; i <= aLen; i++) {
for (int j = 0; j <= bLen; j++) {
std::cout << arr[i][j] << " ";
}
std::cout << "\n";
}
}
int main(void) {
std::string a, b;
int aLen, bLen;
std::cin >> a >> b;
aLen = a.length();
bLen = b.length();
for (int i = 1; i <= aLen; i++) {
for (int j = 1; j <= bLen; j++) {
if (a[i - 1] == b[j - 1]) {
arr[i][j] = arr[i - 1][j - 1] + 1;
} else {
arr[i][j] = std::max(arr[i - 1][j], arr[i][j - 1]);
}
}
}
// printArr(aLen, bLen);
std::cout << arr[aLen][bLen];
}
반성회
이 블로그에 설명이 정말 잘 되어 있다… 감사합니다
어떻게 풀어야 할지 감도 못 잡고 있었는데 블로그 보고 이해함
기본 내용
ACAYKP
CAPCAK
두 문자열을 이용하여 최장 부분 문자열을 뜯어온다고 가정하자
첫 번째 줄은 0으로 초기화한다
아래에서도 나오겠지만 i - 1
인덱스에 접근하는 경우가 생기므로 음수 인덱스 접근 방지를 위해 채워주는 느낌이라고 생각하면 될 것
첫 행부터 채워나간다
A
와C
가 만나는 부분 →A
와C
의 비교 → LCS 없음C
와C
가 만나는 부분 →AC
와C
의 비교 → LCS:C
A
와C
가 만나는 부분 →ACA
와C
의 비교 → LCS:C
Y
와C
가 만나는 부분 →ACAY
와C
의 비교 → LCS:C
K
와C
가 만나는 부분 →ACAYK
와C
의 비교 → LCS:C
P
와C
가 만나는 부분 →ACAYKP
와C
의 비교 → LCS:C
A
와A
가 만나는 부분 →A
와CA
의 비교 → LCS:A
C
와A
가 만나는 부분 →AC
와CA
의 비교 → LCS:C
또는A
A
와A
가 만나는 부분 →ACA
와CA
의 비교 → LCS:CA
- 이때 길이는 각각의 이전 문자열이었던
AC
와C
의 LCS에서 1을 더한 값
- 이때 길이는 각각의 이전 문자열이었던
Y
와A
가 만나는 부분 →ACAY
와CA
의 비교 → LCS:CA
K
와A
가 만나는 부분 →ACAYK
와CA
의 비교 → LCS:CA
P
와A
가 만나는 부분 →ACAYKP
와CA
의 비교 → LCS:CA
부분 문자열이므로 LCS는 더 큰 값이 나오지 않는 이상 이전 값이 유지된다
A
와P
가 만나는 부분 →A
와CAP
의 비교 → LCS:A
C
와P
가 만나는 부분 →AC
와CAP
의 비교 → LCS:C
또는A
A
와P
가 만나는 부분 →ACA
와CAP
의 비교 → LCS:CA
Y
와P
가 만나는 부분 →ACAY
와CAP
의 비교 → LCS:CA
K
와P
가 만나는 부분 →ACAYK
와CAP
의 비교 → LCS:CA
P
와P
가 만나는 부분 →ACAYKP
와CAP
의 비교 → LCS:CAP
- 이때 길이는 각각의 이전 문자열이었던
ACAYK
와CA
의 LCS에서 1을 더한 값
- 이때 길이는 각각의 이전 문자열이었던
A
와C
가 만나는 부분 →A
와CAPC
의 비교 → LCS:A
C
와C
가 만나는 부분 →AC
와CAPC
의 비교 → LCS:AC
A
와C
가 만나는 부분 →ACA
와CAPC
의 비교 → LCS:AC
또는CA
Y
와C
가 만나는 부분 →ACAY
와CAPC
의 비교 → LCS:AC
또는CA
K
와C
가 만나는 부분 →ACAYK
와CAPC
의 비교 → LCS:AC
또는CA
P
와C
가 만나는 부분 →ACAYKP
와CAPC
의 비교 → LCS:CAP
A
와A
가 만나는 부분 →A
와CAPCA
의 비교 → LCS:A
C
와A
가 만나는 부분 →AC
와CAPCA
의 비교 → LCS:AC
A
와A
가 만나는 부분 →ACA
와CAPCA
의 비교 → LCS:ACA
- 이때 길이는 각각의 이전 문자열이었던
AC
와CAPC
의 LCS에서 1을 더한 값
- 이때 길이는 각각의 이전 문자열이었던
Y
와A
가 만나는 부분 →ACAY
와CAPCA
의 비교 → LCS:ACA
K
와A
가 만나는 부분 →ACAYK
와CAPCA
의 비교 → LCS:ACA
P
와A
가 만나는 부분 →ACAYKP
와CAPCA
의 비교 → LCS:ACA
또는CAP
A
와K
가 만나는 부분 →A
와CAPCAK
의 비교 → LCS:A
C
와K
가 만나는 부분 →AC
와CAPCAK
의 비교 → LCS:AC
A
와K
가 만나는 부분 →ACA
와CAPCAK
의 비교 → LCS:ACA
Y
와K
가 만나는 부분 →ACAY
와CAPCAK
의 비교 → LCS:ACA
K
와K
가 만나는 부분 →ACAYK
와CAPCAK
의 비교 → LCS:ACAK
- 이때 길이는 각각의 이전 문자열이었던
ACAY
와CAPCA
의 LCS에서 1을 더한 값
- 이때 길이는 각각의 이전 문자열이었던
P
와K
가 만나는 부분 →ACAYKP
와CAPCAK
의 비교 → LCS:ACAK
문자열 a (ACAYKP) 의 인덱스: i
문자열 b (CAPCAK) 의 인덱스: j 라고 가정
위 표의 배열은 arr이다
여기서 규칙이 2개가 등장하는데,
- 같은 문자를 만날 경우 (
a[i]
==b[j]
), 각각의 이전 문자열의 LCS에서 1 증가한 값을 갖는다 - 오른쪽 아래 대각선으로 1 증가한다는 의미
arr[i][j] = arr[i - 1][j - 1] + 1
- 다른 문자의 경우, 각각의 두 이전 문자열의 LCS 중 큰 값을 이어받는다
arr[i][j] = max(arr[i - 1][j], arr[i][j - 1])
문제가 됐던 코드
for (int i = 0; i < aLen; i++) { // 여기서 0으로 초기화하는 부분
for (int j = 0; j < bLen; j++) { // 여기서 0으로 초기화하는 부분
if (a[i] == b[j]) {
arr[i][j] = arr[i - 1][j - 1] + 1; // 음수 인덱싱 되는 부분
} else {
arr[i][j] = std::max(arr[i - 1][j], arr[i][j - 1]); // 음수 인덱싱 되는 부분
}
}
}
계속 틀렸습니다가 나왔는데 인덱싱 문제였다
C에서는 배열에 음수 인덱스로 접근하면 undefined behavior이라 운이 좋으면 오류 없이 잘 넘어갈 수도 있지만 잘못 걸리면 오류가 발생할 수도 있다는 것
Comments