問題#
【重複のない最長部分文字列】文字列 s
が与えられた場合、重複する文字を含まない 最長部分文字列 の長さを求めてください。
解法 1:スライディングウィンドウ + ハッシュテーブル#
最大長を求める#
Console.WriteLine(LengthOfLongestSubstring("abcabcbb"));
Console.WriteLine(LengthOfLongestSubstring("bbbbb"));
Console.WriteLine(LengthOfLongestSubstring("pwwkew"));
// 指定された文字列内で最大の重複しない部分文字列の長さを取得する
int LengthOfLongestSubstring(string str)
{
if (string.IsNullOrWhiteSpace(str)) return 0;
// 文字 str[right] の最後の出現インデックスをカウントするハッシュテーブル
Dictionary<char, int> dic = new();
// 左ポインタ(-1 または 0 のどちらでも可)、最大の重複しない部分文字列の長さ
int left = -1, res = 0;
// right ポインタを繰り返し増やしてウィンドウを拡大する
for (int right = 0; right < str.Length; right++)
{
//Console.WriteLine($"ウィンドウを右に拡大: [{left}, {right}]");
var currentChar = str[right];
if (dic.ContainsKey(currentChar))
{
// 重複する文字に遭遇したため、左ポインタを重複値のインデックスに更新してウィンドウを縮小する
left = dic[currentChar];
//Console.WriteLine($"ウィンドウを左に縮小: [{left}, {right}]");
}
// ハッシュテーブルを更新:現在の文字の最後の出現インデックスを記録する
dic[currentChar] = right;
// 結果を更新:右ポインタから左ポインタを引いて、閉じた範囲 [left+1, right] の最大の重複しない部分文字列の長さを取得する
// さらに、前回の結果と今回の双ポインタ範囲 [left+1, right] の幅(つまり right -left)の最大値を取得するために Max 関数を使用する
res = Math.Max(res, right - left);
//Console.WriteLine($"------第 {right} ラウンドの結果: {res}------{Environment.NewLine}");
}
return res;
}
最大連続部分文字列を求める#
Console.WriteLine($"結果: {MaxChild("abca2f")}");
Console.WriteLine($"結果: {MaxChild("aabbcc")}");
Console.WriteLine($"結果: {MaxChild("aaaaa")}");
// 最長の重複しない部分文字列(連続)
string MaxChild(string str)
{
if (string.IsNullOrWhiteSpace(str)) return string.Empty;
Dictionary<char, int> dic = new();
int left = 0;
string res = "";
// [left, right]
for (int right = 0; right < str.Length; right++)
{
// 現在の文字
char currentChar = str[right];
// すでに出現しているかどうかをチェックし、出現している場合は左境界を重複したインデックスに縮小する
if (dic.ContainsKey(currentChar))
{
// 含まれている場合、重複する文字列が表示されるため、ウィンドウを縮小する
left = dic[currentChar] + 1;
//Console.WriteLine($"update {currentChar} {right}");
// インデックスを更新する
//dic[currentChar] = right;
dic.Clear();
}
dic[currentChar] = right;
// 結果を更新する
string sub = str.Substring(left, right - left + 1);
if (sub.Length > res.Length)
{
res = sub;
}
}
return res;
}
(学習中)解法 2:動的計画法 + ハッシュテーブル#
(K 神の図解を参照)
参考:#
- 3. 重複のない最長部分文字列 - LeetCode
- スライディングウィンドウの詳細:スライディングウィンドウの詳細 - LeetCode
- K 神の図解:3. 重複のない最長部分文字列 - LeetCode