今天拿到了一个Go语言的题目,计算字符串中不重复最长子串长度,原题是:
https://leetcode.com/problems/longest-substring-without-repeating-characters/
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.
做为初学者,我自己经过不懈努力,写了一个不是很好的算法,再次过程中,我对map的遍历有了进一步的认识,之前总认为遍历结果顺序不同,对程序没有什么影响,直到遇到这个问题。
package main
import (
"fmt"
)
/*
算法描述:
s:目标字符串
maxLength:记录最长子串长度,最终要返回给主程序的值
counter:计数器,记录字符在字符串s中的位置
countMap:记录字符编码和字符位置,因为range字符串值为int32对应是字符的编码
执行过程:遍历s,字符编码给v,判断countMap中是否有v,如果没有,将v最为key
couter做为value存入countMap中;如果有,将不大于countMap[v]的值删除,再记录当前值,
计算countMap长度,如果不小与maxLength,maxLength等于countMap长度,counter加1
进入下一次循环。
*/
func lengthOfLongestSubstring(s string) int {
maxLength := 0
counter := 1
countMap := make(map[int32]int)
for _, v := range(s){
if countMap[v] != 0{
for key, value := range(countMap){
if value <= countMap[v]{
delete(countMap, key)
}
}
}
countMap[v] = counter
if len(countMap) >= maxLength{
maxLength = len(countMap)
}
counter += 1
}
return maxLength
}
func main() {
var str string = "jbpnbwwd"
length := lengthOfLongestSubstring(str)
fmt.Println(length)
}
问题
逻辑上是没有什么问题,但是运行结果不理想,正确结果应该是4,但是有时候会出现5和6。
我反复推敲调试才发现多了个等于号,你们直到是哪个等于号吗,不妨遮住下面的内容思考一下。
Are you OK?(雷总名言借用一下)
就是这里。
解释:
因为map遍历是随即的,所以你不知道哪个值会被先拿出来。
如果按照顺序的话,肯定是没有问题的,先拿出小于的,小于的通通删掉,再是等于,等于的也删掉,后面再比较的时候countMap就不在countMap中了是默认值0了,也就不用比较了。
随即的话,就不一样了,如果等于提前被拿出来,删除后,再比较的话,countMap[v]=0了,即使countMap里面还有符合条件的也拿不出来了。这是算法上的失误。
解决办法:
1、将countMap[v]先赋值给一个变量,再用变量去比较;
func lengthOfLongestSubstring(s string) int {
maxLength := 0
counter := 1
countMap := make(map[int32]int)
for _, v := range(s){
if countMap[v] != 0{
tmp := countMap[v]
for key, value := range(countMap){
if value <= tmp{
delete(countMap, key)
}
}
}
countMap[v] = counter
if len(countMap) >= maxLength{
maxLength = len(countMap)
}
counter += 1
}
return maxLength
}
2、将等于号去掉就可以了,就不多解释了。
func lengthOfLongestSubstring(s string) int {
maxLength := 0
counter := 1
countMap := make(map[int32]int)
for _, v := range(s){
if countMap[v] != 0{
for key, value := range(countMap){
if value < countMap[v]{
delete(countMap, key)
}
}
}
countMap[v] = counter
if len(countMap) >= maxLength{
maxLength = len(countMap)
}
counter += 1
}
return maxLength
}
总结:
我的算法执行效率比较低,有两层循环,但是基本满足要求。下面看一下大神的算法,不做解释,膜拜就行了。
func lengthOfLongestSubstring(s string) int {
lastOccurred := make(map[rune]int)
start := 0
maxLength := 0
for i, ch := range []rune(s) {
if lastI, ok := lastOccurred[ch]; ok && lastI >= start {
start = lastI + 1
}
if i-start+1 > maxLength {
maxLength = i - start + 1
}
lastOccurred[ch] = i
}
return maxLength
}
应该没有什么版权的问题,除了最后用了点大神的代码,别的都是本人手码的,如果有版权、语法、错别字等问题,欢迎留言或E-mail(vnths@qq.com)给我,我看到后,会及时处理。
欢迎努力中的同学来访,MAIL ME! I’m Liby. Thank you!