本文共 5275 字,大约阅读时间需要 17 分钟。
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
案例:
s = “leetcode”
返回 0.s = “loveleetcode”
返回 2.
注意事项:您可以假定该字符串只包含小写字母。
方法一:
执行用时 :12 ms/16 ms, 击败了66.08%/62.57% 的用户 内存消耗 :5.8 MB, 击败了14.63%的用户嵌套循环,依次遍历,在几个方法中并不是速度最慢的。
func firstUniqChar1(s string) int { l := len(s) - 1 for i := 0; i <= l; i++ { r := 1 for j := 0; j <= l; j++ { if i != j && s[i] == s[j] { r = 0 break } } if r == 1 { return i } } return -1}
方法二:
执行用时 :144 ms, 击败了5.19% 的用户 内存消耗 :5.8 MB, 击败了14.63%的用户利用go的方法
遍历过程中一旦某个字母只有唯一一个,立刻停止循环返回其索引号strings.Count()
,遍历一次,计算每个字母出现的个数,
func firstUniqChar2(s string) int { for i := range s { c := strings.Count(s, string(s[i])) if c == 1 { return i } } return -1}
方法三:
执行用时 :20 ms, 击败了60.58% 的用户 内存消耗 :5.7 MB, 击败了95.12%的用户利用go的方法
如果相同,且是第一次检测,则说明是唯一元素,返回索引号 本方法需创建一个map,却消耗内存最低strings.LastIndexByte()
,遍历当前元素与字符串中最后一个相同元素的索引号是否一致
func firstUniqChar3(s string) int { v := make(map[int]int, 26) for i := range s { c := strings.LastIndexByte(s, s[i]) if c == i && v[c] != 1 { return i } v[c] = 1 } return -1}
方法四:
执行用时 :40 ms/36 ms, 击败了46.73%/54.62% 的用户 内存消耗 :5.7 MB, 击败了95.12%的用户第一次遍历字符串中每个元素,用map记录元素出现的次数,没有使用go自带的
第二次遍历字符串每个元素,当发现该元素在map中的值为1则意味着该元素只出现一次,立刻返回索引号 本方法与方法二思路相同,但内存占用和执行效率提升N倍 本方法统计了所有的元素的出现次数,而方法三只获得最后一个元素的位置,因此本方法执行效率慢了一倍。strings.Count()
方法
func firstUniqChar4(s string) int { r := make(map[rune]int, 26) for _, v := range s { r[v]++ } for i, v := range s { if r[v] == 1 { return i } } return -1}
方法五:
执行用时 :8 ms,击败了88.08% 的用户 内存消耗 :5.8 MB, 击败了14.63%的用户取巧的方法,因为题目里说了都是小写字母,否则数组
又因为都是小写字母,因此r
的长度无法确定v-97
可得到0~26,正好用于数组索引 第一次遍历字符串计算元素出现次数 第二次遍历字符串遇到出现一次的元素返回其索引 方法二、方法四、方法五思路一致,都是统计元素出现次数,但方法五执行效率最高,方法四内存占用最少 推荐方法四,可以用于非小写字母的字符串统计,而方法五适用面太小
func firstUniqChar5(s string) int { // ASCII数值:a-z:97-122,A-Z:65-90,0-9:48-57。 r := [26]int{ } for _, v := range s { r[v-97]++ } for i, v := range s { if r[v-97] == 1 { return i } } return -1}
方法六:
执行用时 :12 ms, 击败了66.15% 的用户 内存消耗 :6 MB, 击败了7.32%的用户本方法是将方法三中的map改为了切片,但效果不明显,执行效率增加,但是内存占用也增加了~~
这是因为当s
为类似"aabbccddefggadfdaefdfaefaggjfghtrgregtrujuoiolokuhtrgrfe"
,在创建切片的时候就会创建一个同样长度的切片,否则如果使用append()
,每次更改内存地址,相比速度会减慢,没有必要了。
func firstUniqChar6(s string) int { v := make([]int, len(s)) for i := range s { c := strings.LastIndexByte(s, s[i]) if c == i && v[c] != 1 { return i } v[c] = 1 } return -1}
方法七:
执行用时 :12 ms, 击败了66.15% 的用户 内存消耗 :5.8 MB, 击败了14.63%的用户想让方法六中的切片固定为一个数组,看看会不会有所提升于是创建了方法七
果然内存消耗是降低了,但执行效率并没什么改变 方法三中的map可变长度又能自定义键名,反倒省了很多事
func firstUniqChar7(s string) int { r := [26]int{ } for i, v := range s { c := strings.LastIndexByte(s, s[i]) if c == i && r[v-97] != 1 { return i } r[v-97] = 1 } return -1}
这里需要拓展的知识点有两个:
我们常用的记住下面的就行了,实际使用的时候结合实际情况,发挥创意:
0~31及127(共33个)是控制字符或通信专用字符(其余为可显示字符),如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(响铃)等;通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;ASCII值为8、9、10
和13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响 [1] 。
32~126(共95个)是字符(32是空格),其中48~57为0到9十个阿拉伯数字。
65~90为26个大写英文字母,97~122号为26个小写英文字母,其余为一些标点符号、运算符号等。
参考:
import ( "fmt" "strings")func main() { fmt.Println(strings.Contains("widuu", "wi")) //true fmt.Println(strings.Contains("wi", "widuu")) //false}
import ( "fmt" "strings")func main() { fmt.Println(strings.ContainsAny("widuu", "w&d")) //true}
import ( "fmt" "strings")func main() { fmt.Println(strings.ContainsRune("widuu", rune('w'))) //true fmt.Println(strings.ContainsRune("widuu", 20)) //fasle}
import ( "fmt" "strings")func main() { fmt.Println(strings.Count("widuu", "uu")) //1 fmt.Println(strings.Count("widuu", "u")) //2}
import ( "fmt" "strings")func main() { fmt.Println(strings.Index("widuu", "i")) //1 fmt.Println(strings.Index("widuu", "u")) //3}
import ( "fmt" "strings")func main() { fmt.Println(strings.IndexAny("widuu", "u")) //3}
import ( "fmt" "strings")func main() { fmt.Println(strings.IndexByte("hello xiaowei", 'x')) //6}
import ( "fmt" "strings")func main() { fmt.Println(strings.IndexRune("widuu", rune('w'))) //0}
import ( "fmt" "strings")func main() { fmt.Println(strings.IndexFunc("nihaoma", split)) //3}func split(r rune) bool { if r == 'a' { return true } return false}
import ( "fmt" "strings")func main() { fmt.Println(strings.LastIndex("widuu", "u")) // 4}
import ( "fmt" "strings")func main() { fmt.Println(strings.LastIndexAny("widuu", "u")) // 4}
转载地址:http://ctkpi.baihongyu.com/