最开始提交了几次都是超出时间限制,后来修改了一下,只遍历一遍字符串,然后没有其他循环,时间复杂度控制在O(n),才提交通过:
func lengthOfLongestSubstring(s string) int { var ( length int //最后返回值 begin int //每个子串的起始位置 ) //使用这个map来判定当前子串中是否出现了重复的字符 tmpMap := make(map[byte]int, len(s)) for i := 0; i < len(s); i++ { //只遍历这一次,没有其他循环,不然就超出时间限制 //这一步很关键,首先使用OK来判断当前子串中是否存在循环当前遍历到的字符,如果不存在,就把这个字符和它的位置加入map //如果这个字符存在于map中,那么就判断这个字符的位置和begin谁更靠前 //如果这个字符的位置更靠前,说明这个字符出现的位置不是当前子串,那么也相当于在当前子串中第一次出现,然后更新map中这个字符的位置 //如果begin更靠前,说明在当前子串中出现了重复字符,需要计算当前无重复字符子串的长度了 if index, OK := tmpMap[s[i]]; !OK || index < begin { tmpMap[s[i]] = i //更新位置 if i == len(s)-1 { //这里计算的长度是给定字符串的最后一个子串的长度 if (i - begin + 1) > length { length = (i - begin + 1) } } } else { //当遇到重复字符的时候,计算子串的长度 if (i - begin) > length { length = (i - begin) } //更新下一个子串的起始位置 begin = tmpMap[s[i]] + 1 //更新遍历到的字符在map中的位置 tmpMap[s[i]] = i } } return length }
使用i和begin的双指针的方式,这样只需要遍历一次字符串就可以了,而用begin和当前出现的重复字符的位置的先后比较,也减少了遍历map的这个循环,从而达到了只需要一次循环,时间复杂度为O(n)的目的。