/*
* Problem :: 5528 / 공통 부분 문자열
*
* Kind :: Dynamic Programming
*
* Insight
* - LCS = Longest Common Subsequence 가 아니라
* LCS = Longest Common Substring 이다
* + subsequence 는 연속적이지 않은 부분 문자열이고
* substring 은 연속적인 부분 문자열이다
* # 기존에 알고 있던 위의 LCS 알고리즘을 조금 변경해서 써야할 것 같다
*
* - 문자열 u 와 v 가 있을 때
* 기존 LCS(subsequence) 알고리즘에서는
* dp[i][j] = u 의 i 번째 문자까지와 v 의 j 번째 문자까지의 max(len(LCS)) 였다
* + 알고리즘은 다음과 같다
* if (u[i] == v[i]) { dp[i][j] = dp[i-1][j-1] + 1; }
* else { dp[i][j] = max(dp[i][j-1], dp[i-1][j]); }
* # 위의 LCS 알고리즘에서 subsequence 가 아니라 substring 의 경우에는
* 연속되어야 하기 때문에 else 문의 max(dp[i][j-1], dp[i-1][j]) 는 옳지 않다
* -> i 번째 문자로끝나는 substring 과 j 번째 문자로끝나는 substring 이어야 하니까
* -> 그렇다면 else 문만 빼면 될 것 같은데...? <= 진짜 else 문만 뺐더니 통과했다!
* 지금생각해보니 u[i] 와 v[j] 가 다르면 dp[i][j] = 0 일 수밖에 없다
*
* Point
* - dp 를 나중에 모두 탐색하면서 최댓값 찾지 귀찮아서
* 그때그때 값의 갱신이 일어날 때마다 최댓값을 찾아주었다
*
* - 편의상 문자열의 첫 번째 글자를 인덱스 0 으로 간주하였다
* + 문자열 u 의 i 번째 글자 = u[i-1]
* 문자열 v 의 j 번째 글자 = V[j-1]
*
* - u[i] == v[j] 여서 LCS 에 속한다면
* 이 글자는 또 다른 LCS 에 동시에 속할 수 없다
*/
//
// BOJ
// ver.C++
//
// Created by GGlifer
//
// Open Source
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define endl '\n'
// Set up : Global Variables
/* None */
// Set up : Functions Declaration
/* None */
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
string u; cin >> u;
string v; cin >> v;
// Process
int lu = u.length();
int lv = v.length();
/* dp[i][j] = u 의 i 번째 글짜까지와 v 의 j 번째 글짜까지의 max(len(LCS))
* 여기서 S 는 Subsequence 가 아닌 Substring 을 의미 */
int dp[lu+1][lv+1];
memset(dp, 0, sizeof(dp)); /* 초기화 */
int ans = 0;
for (int i=1; i<=lu; i++) {
for (int j=1; j<=lv; j++) {
if (u[i-1] == v[j-1]) {
dp[i][j] = dp[i-1][j-1]+1;
ans = max(ans, dp[i][j]);
}
}
}
// Control : Output
cout << ans << endl;
}
// Helper Functions
/* None */