leetcode算法:3.无重复字符的最长子串
无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
思考
考虑空间复杂度
- 要求空间复杂度O(1)
- 允许空间复杂度O(n)
解答
- 对于要求空间复杂度O(1)的这种情况,需要双层循环暴力搜索。
- 对于允许空间复杂度O(n)的这种情况,空间换时间,可以达到时间复杂度O(n)。思路是用一个指针指示不重复字符串的开始位置,利用这个指针计算当前字符串长度,然后从第一个字符串开始搜索,每搜索一个字符串时查看是否有重复,没有重复继续下一个并更新不重复字符长度,有则将指针移动前面那个重复字符的下一字符处。
举个例子: 对于abcabc,首先指针p指向index为0的a,然后循环遍历字符串,遍历到index为1的b时,指针p指向a(index为0),此时未出现重复字符串,当前子串最大长度为index(b) - p = 1-0+1=2,然后继续遍历移动字符c,同理,此时index为2(字符c),指针p指向a(index为0),当前子串最大长度为index(b) - p = 1-0+1=2,继续遍历到字符a,此时a重复,从map中查询到前面a的index为0,则为保持不重复字符串的特性,需将指针p移到到a的下一位,因此p=index(a)+1。每次都计算最长子串长度,直到遍历结束。
package algo func lengthOfLongestSubstring(s string) int { if len(s) < 1 { return 0 } if len(s) == 1 { return 1 } var ( charMap = make(map[int32]int) maxLength = 0 uniqueCharStringStart = 0 ) for index, each := range s { // 判断字符是否重复 if at, ok := charMap[each]; ok { // 重复则将不重复字符串首字符位置指示符移动到重复字符后 if at >= uniqueCharStringStart { uniqueCharStringStart = at + 1 } } if index-uniqueCharStringStart+1 > maxLength { maxLength = index - uniqueCharStringStart + 1 } charMap[each] = index } return maxLength }
单元测试
package algo import ( "testing" ) func TestLengthOfLongestSubstring(t *testing.T) { s1 := "abcdabcd" s2 := "abcabc" s3 := "aaaaaa" s4 := "abcddcba" s5 := "abcdefg" s6 := "" s7 := " " s8 := " " s9 := "dvdf" if lengthOfLongestSubstring(s1) != 4 { t.Fatal() } if lengthOfLongestSubstring(s2) != 3 { t.Fatal() } if lengthOfLongestSubstring(s3) != 1 { t.Fatal() } if lengthOfLongestSubstring(s4) != 4 { t.Fatal() } if lengthOfLongestSubstring(s5) != 7 { t.Fatal() } if lengthOfLongestSubstring(s6) != 0 { t.Fatal() } if lengthOfLongestSubstring(s7) != 1 { t.Fatal() } if lengthOfLongestSubstring(s8) != 1 { t.Fatal() } if lengthOfLongestSubstring(s9) != 3 { t.Fatal() } }