例如:
输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"abc",所以其
长度为 3。
方法一:
/// <summary> /// 给定一个字符串,找出其中不含有重复字符的 最长子串 的长度。 /// </summary> /// <param name="str"></param> /// <returns></returns> public int LengthOfLongestSubstring(string str) { int resLength = 0; int strLength = str.Length; for (int i = 0; i < strLength; i++) { for (int j = i + 1; j < strLength; j++) { //这里能确定str的所有子串 HashSet<string> hashSet = new HashSet<string>(); bool isExists = false; for (int z = i; z < j; z++) { string strChildren = str.Substring(z, 1); if (hashSet.Contains(strChildren)) { isExists = true; break; } else { hashSet.Add(strChildren); } } if (!isExists) { //这里是不存在相同的才给resLength赋值 resLength = Math.Max(resLength, j - i); } } } return resLength; }
方法二:滑动窗口
在方法一中,我们会反复检查一个子字符串是否含有有重复的字符,但这是没有必要的。如果从索引 i 到 j - 1 之间的子字符串sij? 已经被检查为没有重复字符。我们只需要检查 s[j] 对应的字符是否已经存在于子字符串 sij? 中。
要检查一个字符是否已经在子字符串中,我们可以检查整个子字符串,这将产生一个复杂度为 O(n2) 的算法,但我们可以做得更好。
通过使用 HashSet 作为滑动窗口,我们可以用 O(1) 的时间来完成对字符是否在当前的子字符串中的检查。
滑动窗口是数组/字符串问题中常用的抽象概念。 窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i, j)(左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将 [i, j)向右滑动 11 个元素,则它将变为 [i+1, j+1)(左闭,右开)。
回到我们的问题,我们使用 HashSet 将字符存储在当前窗口 [i, j)(最初 j = i)中。 然后我们向右侧滑动索引 j,如果它不在 HashSet 中,我们会继续滑动 j。直到 s[j] 已经存在于 HashSet 中。此时,我们找到的没有重复字符的最长子字符串将会以索引 i开头。如果我们对所有的 i 这样做,就可以得到答案。
public int LengthOfLongestSubstring(string str) { int resLength = 0; int strLength = str.Length; int i = 0, j = 0; HashSet<string> hashSet = new HashSet<string>(); while (i < strLength && j < strLength) { string oneStrJ = str.Substring(j,1); if (!hashSet.Contains(oneStrJ)) { hashSet.Add(oneStrJ); j++; resLength = Math.Max(resLength,j-i); } else { string oneStrI = str.Substring(i, 1); hashSet.Remove(oneStrI); i++; } } return resLength; }
给定一个字符串,找出其中不含有重复字符的 最长子串 的长度(来自LeetCood)
原文:https://www.cnblogs.com/xiahaitao/p/10348813.html