题目:给定一个字符串,请你找出其中不含有重复字符的最长字串的长度。
示例1:
输入:“abcabcbb”
输出:3
解释:因为无重复字符的最长子串是“abc",所以其长度为3.
示例2:
输入:”bbbbb"
输出:1
解释:因为无重复字符的最长子串是"b",所以其长度为1
示例3:
输入:“pwwkew"
输出:3
解释:因为无重复字符的最长子串是”wke",所以其长度为3。
请注意,你的答案必须是子串的长度,”pwke“是一个子序列,不是子串。
解法一:暴力穷举法。找出所给字符串所有的子串,然后以用 map 算出每个子串是否包含重复字符。这种解法比较容易想到和实现,但是时间复杂度也是很大的,当字符串很大时,暴力穷举法时不可取的。在LeetCode上提交也会超时。具体实现如下代码所示:
//RepeatCheck函数:用于检查n字符串s中是否有重复的字符
func RepeatCheck(s string) bool {
//利用map存储字符串s中的每个字符
var mapper map[byte]int
mapper = make(map[byte]int)
var i int
for i = 0; i < len(s); i++ {
mapper[s[i]]++
}
/*判断map的长度与字符串s的长度是否相等。如果不相等,
说明有重复字符*/
if len(mapper) == len(s) {
return false
}
return true
}
func lengthOfLongestSubstring(s string) int {
//对长度为1的字符串进行特殊处理
if len(s) == 1 {
return 1
}
var i, j int
var maxLen int
/*两层循环获取字符串所有的子串*/
for i = 0; i < len(s); i++ {
for j = i + 1; j <= len(s); j++ {
subStr := s[i:j]
//判断每个子串是否有重复得分字符
if RepeatCheck(subStr) == false {
if len(subStr) > maxLen {
maxLen = len(subStr)
}
}
}
}
return maxLen
}
解法二:利用滑动窗口原理,先固定字符串左边,然后移动字符串右边,直到该子串出现重复字符就停止,然后在移动字符串左边的下一位。如此重复,大大减少了子串的搜索空间,从而减少了时间复杂度,提高了效率。
举个例子:字符串"abab",利用穷举法就需要算出 a,ab,aba,abab,b,ba,bab,a,ab,b.利用滑动窗口的思想,只需要算出a,ab,(aba,出现重复字符,接下来的子串不需要计算)b,ba,(bab,出现重复字符),a,ab,b。
具体实现如下代b码所示:
func lengthOfLongestSubstring(s string) int {
if len(s) == 1 {
return 1
}
var i, j int
var maxLen int
for i = 0; i < len(s); i++ {
//利用mapper来计算从i到j的子串是否有重复字符
var mapper map[byte]int
mapper = make(map[byte]int)
mapper[s[i]]++
//j不断向右移动,直至遇到mapper中出现重复字符,即ok为true值
for j = i + 1; j < len(s); j++ {
_, ok := mapper[s[j]]
mapper[s[j]]++
/*当出现重复字符时,判断从i到j的子串长度是否比maxLen大,
并停止对后面子串的搜索。
*/
if ok == true {
if j-i > maxLen {
maxLen = j - i
}
break
}
}
//当来到字符串末尾时,进行特殊处理
if j == len(s) {
if j-i > maxLen {
maxLen = j - i
}
}
}
return maxLen
}