Problem:
共通部分文字列

問題

2 個の文字列が与えられたとき, 両方の文字列に含まれる文字列のうち最も長いものを探し, その長さを答えるプログラムを作成せよ.

ここで, 文字列 s が文字列 t に含まれるとは, t の中に s が連続して現れることをいう. 空文字列, すなわち長さ 0 の文字列は, どんな文字列にも含まれる. 例えば, 文字列 ABRACADABRA には次の文字列が含まれる: ABRA, RAC, D, ACADABRA, ABRACADABRA,空文字列など. 一方, 文字列 ABRACADABRA には次の文字列は含まれない: ABRC, RAA,BA, K など.

例

例 1: 文字列として ABRACADABRA と ECADADABRBCRDARA が与えられた場合, 両方に含まれる文字列には CA や CADA や ADABR や空文字列などがある. そのうち最も長いのは ADABR であり, その長さは 5 である. 2 個の文字列の中に含まれる ADABR
の位置を以下に示す.

ABRACADABRA

ECADADABRBCRDARA

例 2: 文字列として UPWJCIRUCAXIIRGL と SBQNYBSBZDFNEV が与えられた場合, 両方に含まれる文字列は空文字列のみであり, その長さは 0 である.

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

入力は 2 行からなり, 1 行目に 1 個目の文字列が, 2 行目に 2 個目の文字列が与えられる. 文字列は英大文字からなり, 各々の文字列の長さは 1 以上 4000 以下である.

採点用データのうち, 配点の 30% 分については, 各々の文字列の長さは 1 以上 50以下である.

入力の終わりは EOF で示される. データセットの数は 10 を超えない．

出力

データセットごとに与えられた 2 個の文字列の両方に含まれる文字列のうち最も長いものの長さを 1 行に出力する.

入出力例

入力例

ABRACADABRA
ECADADABRBCRDARA
UPWJCIRUCAXIIRGL
SBQNYBSBZDFNEV

出力例

5
0

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in C# (judge verdict: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace _528_CommonSub_String
{
	class Program
	{
		static void Main ( string[] args )
		{
			string inputStr;
			string inputStr2;

			//input
			while ((inputStr = Console.ReadLine ()) != null && (inputStr2 = Console.ReadLine ()) != null)
			{
				//process
				int maxLength = Function (inputStr, inputStr2);

				//output
				Console.WriteLine (maxLength);
			}
		}

		static int Function ( string str1, string str2 )
		{
			string minString;
			string maxString;

			if (str1.Length < str2.Length)
			{
				minString = str1;
				maxString = str2;
			}
			else
			{
				minString = str2;
				maxString = str1;
			}

			int index = 0;
			StringBuilder foundStr = new StringBuilder (minString.Length);
			int maxLength = 0;

			while (index < minString.Length)
			{
				char ch = minString[index];
				List<int> indexList = new List<int> (minString.Length / 5);
				bool isFirst = true;

				//1????????????????????????????????????
				do
				{
					int chIndex = 0;
					if (isFirst)
					{
						chIndex = maxString.IndexOf (ch);
						isFirst = false;
					}
					else
					{
						chIndex = maxString.IndexOf (ch, indexList.Last () + 1);
					}

					if (chIndex != -1)
						indexList.Add (chIndex);
					else
						break;
				} while (true);

				//1?????§??????????????£??????
				if (0 < indexList.Count)
				{
					foundStr.Append (ch);
					index++;

					while (index < minString.Length)
					{
						List<int> tmpList = new List<int> (indexList.Count);
						char searchChar = minString[index];

						foreach (var item in indexList)
						{
							int nextIndex = item + 1;
							if (nextIndex < maxString.Length)
							{
								if (searchChar == maxString[nextIndex])
								{
									tmpList.Add (nextIndex);
								}
							}
						}

						indexList = new List<int> (tmpList);

						if (0 < indexList.Count)
						{
							foundStr.Append (searchChar);
							index++;
						}
						else
						{
							maxLength = Math.Max (foundStr.Length, maxLength);

							foundStr.Remove (0, 1);

							if (0 < foundStr.Length)
							{
								indexList.Clear ();
								isFirst = true;

								do
								{
									int chIndex = 0;
									if (isFirst)
									{
										chIndex = maxString.IndexOf (foundStr.ToString ());
										isFirst = false;
									}
									else
									{
										chIndex = maxString.IndexOf (foundStr.ToString (), indexList.Last () + 1);
									}

									if (chIndex != -1)
										indexList.Add (chIndex);
									else
										break;
								} while (true);

								for (int lp = 0; lp < indexList.Count; lp++)
								{
									indexList[lp] += foundStr.Length - 1;
								}
							}
							else
							{
								break;
							}
						}
					}
				}
				else
				{
					index++;
				}
			}

			maxLength = Math.Max (foundStr.Length, maxLength);
			return maxLength;
		}
	}
}