题目来自于LeetCode(https://leetcode-cn.com)。
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
解法一:暴力法(耗时468ms,内存6.6M)
两重循环对每个元素进行判断,若存在于map中,说明碰到相同的了,退出内层循环;反之则将元素加入map,计数加1;比较max和num,将最大值赋给max。
代码如下:
func lengthOfLongestSubstring(s string) int {
slen := len(s)
max := 0
for i:=0;i<slen;i++ {
res := make(map[string]string)
num := 0
for j:=i;j<slen;j++{
str := s[j:j+1]
if _,ok:=res[str];!ok {
res[str] = str
num++
}else{
break
}
}
if max < num{
max = num
}
}
return max
}
解法二:设置标量,进行判断(耗时36ms,内存2.6M)
考虑到两层循环,时间复杂度肯定为O(n方),就思考用一个循环解决,于是设置两个标量,用来进行循环对比,时间复杂度降低到O(n)。思路看代码注释。strings.Index实际可能用到循环,所以时间复杂度还是可能为O(n方)
代码如下:
func lengthOfLongestSubstring(s string) int {
slen := len(s)
if slen == 1 || slen == 0 {
return slen
}
max := 0
start := 0
end := 1
for start < slen && end < slen {//循环条件
var l = 0
// fmt.Println("----",start,end,s[start:start+1],s[end:end+1],max)
if s[start] == s[end]{//相等,说明不重复字串到此为止,算出长度
l = end - start
if max < l {
max = l
}
start++
end = start + 1
}else{
end++
l = end - start
if max < l {
max = l
}
if max == slen {//最大的等于了长度,则说明,最长字串为自己
break
}
if end >= slen{//如果end大于等于了截止条件,退出
break
}
str := s[start:end]
substr := s[end:end+1]
index := strings.Index(str,substr)
if index != -1 {//前面的字串含有了新的字符,则说明有了,将start置为start+index+1,end置为start+1
start = start + index +1
end = start + 1
}
}
// fmt.Println("++++",start,end,max)
}
return max
}