Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc"
, with the length of 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b"
, with the length of 1.
Example 3:
Input: "pwwkew"
Output: 3
Explanation: The answer is "wke"
, with the length of 3.
Note that the answer must be a substring, "pwke"
is a subsequence and not a substring.
暴力搜索
这道题乍一看很简单,因为是返回长度,因此考虑从长到短搜索,搜索到没有重复的直接返回就可以。
1 public class Solution { 2 public int LengthOfLongestSubstring(string s) { 3 if (string.IsNullOrEmpty(s)) return 0; 4 int length = s.Length; 5 if (length == 1) return 1; 6 while(length > 1) 7 { 8 for (int i = 0; i < s.Length - length + 1; i++) 9 { 10 if (IsNoneRepeatCharString(s.Substring(i,length))) 11 return length; 12 } 13 length--; 14 } 15 return 1; 16 } 17 18 private bool IsNoneRepeatCharString(string s) 19 { 20 HashSet<char> charSet = new HashSet<char>(); 21 foreach (char c in s) 22 { 23 if (charSet.Contains(c)) return false; 24 charSet.Add(c); 25 } 26 return true; 27 } 28 }
Submit后发现超时了,testcase是一个巨长的字符串。
上面的方法虽然不用遍历所有子串,但到底来说还是Brute,时间复杂度还是O(n3)。
主要问题出现在判断重复子串的方法上,其实做了很多不必要的计算。
使用双指针的滑窗法
对于字符串"abcabd"来说,判断完子串"abc"后只要再判断下一个字符在不在上一个子串中。
控制两个指针start和end,当下一个字符在子串中存在时,更新start的位置。
1 public class Solution { 2 public int LengthOfLongestSubstring(string s) { 3 //if (string.IsNullOrEmpty(s)) return 0; 4 int length = s.Length; 5 Dictionary<char, int> dict = new Dictionary<char, int>(); 6 int result = 0; 7 for (int start = 0, end = 0; end < length; end++) 8 { 9 if (dict.ContainsKey(s[end])) 10 { 11 start = Math.Max(start, dict[s[end]]); 12 dict[s[end]] = end + 1; 13 } 14 else 15 { 16 dict.Add(s[end], end + 1); 17 } 18 result = Math.Max(result, end - start + 1); 19 } 20 return result; 21 } 22 }