本文共 4129 字,大约阅读时间需要 13 分钟。
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “” 解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z 。方法一:
执行用时 :0 ms,击败了100.00% 的用户 内存消耗 :2.4 MB, 击败了27.91%的用户以字符串长度最短的为参考源,依次比对找到不匹配的跳出,比较符合本人一般的思维模式
func longestCommonPrefix1(strs []string) string { s := "" l := 0 j := 0 n := 0 m := len(strs) switch m { case 0: return "" case 1: return strs[0] } // 找到字符最少的字符串 for i, v := range strs { // 如果有一个字符串为空,则跳出 if len(v) == 0 { return "" } // 选择最小字符数的 if len(v) < l || l == 0 { l = len(v) j = i } } // 以字符最少的字符串进行循环 for i, v := range strs[j] { // 遍历所有字符串 for _, y := range strs { //如果字符相同,则+1 if string(v) == string(y[i]) { n++ } } // 如果n的数量和strs的长度相同,则表示都存在该字符,继续循环,否则跳出并返回s if n == len(strs) { s += string(v) n = 0 } else { return s } } return s}
方法二:
执行用时 :0 ms, 击败了100.00% 的用户 内存消耗 :2.4 MB, 击败了89.71%的用户任意一个元素都可以作为参考源,而不是方法一中必须使用字符串长度最短的那个作为参考源。
效率差不多,但是内存消耗似乎稍稍降低了一点点。
func longestCommonPrefix2(strs []string) string { // 先排除掉一些 l := len(strs) switch l { // strs为空 case 0: return "" // strs仅一个元素 case 1: return strs[0] } // 设定第一个元素作为前缀的参考源 p := strs[0] // 循环时不含参考源(第一个参考源),少一次比较 for _, x := range strs[1:] { // 本次元素的长度,内层循环多次需要用到 l = len(x) // 参考源(第一个元素)的各个字符 依次匹配 本元素对应位置的字符, // 一发现有不匹配的就跳出,并修改参考源 for i := range p { //如果该字符串长度比i的值小了,则表示该字符串已经到头,这样p就停止在本位置 if i >= l { // p截取最新的,并且跳出循环,下一次循环使用最新的p p = p[:l] break } // 如果同位置字符与参考源同位置字符不同,则修改参考源 if x[i] != p[i] { // p截取最新的,并且跳出循环,下一次循环使用最新的p p = p[:i] // 这里必须跳出终止本次循环,回到外层循环,找到strs的下一个元素再进行比对 break } } } return p}
本题在算法层面没什么难度,就是按照一般的思路走就行了,方法二比方法一升级一点。
本题反倒让我在语言层面有所学习:
go语言中字符串默认情况下就是个[]uint8
(别名:[]byte
)的切片,因此可以直接用切片的方式对其进行切割,而输出的时候又是正常的字符串,例题如下。 s := "a测,123试"fmt.Println(s[:1]) //输出:a,表明英文占1位fmt.Println(s[1:4]) //输出:测,表明中文占3位fmt.Println(s[4:7]) //输出:,,表明中文符号占3位fmt.Println(s[7:10]) //输出:123,表明数字占1位/* 输出a测,123*/
如果使用默认方式,那么当遇到中文等字符的时候,就会占用三个位置,这时使用不当就可能出现乱码。那么为了防止出错,我们可以提前将字符串切片改为[]int32
(别名[]rune
)形式,输出时再利用string()
变回字符串,例题如下。
t := []int32("a测,123试")fmt.Println(t[0], string(t[0])) // 英文占一位fmt.Println(t[1], string(t[1])) // 中文占1位fmt.Println(t[2], string(t[2])) // 中文符号占1位fmt.Println(t[3:6], string(t[3:6])) //数字占1位// 97 a// 27979 测// 65292 ,// [49 50 51] 123
[]uint8
(别名[]byte
)模式下获得的内容可以直接输出,比如fmt.Println(s[7:10])
[]int32
(别名[]rune
)模式下获得的内容输出后为int32
类型的数值 使用for循环遍历字符串的时候,直接取值v
的类型为int32
(别名rune
),通过索引i
取值的类型为int32
(别名rune
)。在有中文情况下,i
的值可能会有间隔 r := "a测,123试"for i, v := range r { fmt.Printf("%v、v类型:%T,v值:%v;r[i]类型:%T,r[i]值:%v\n", i, v, v, r[i], r[i])}// 0、v类型:int32,v值:97;r[i]类型:uint8,r[i]值:97// 1、v类型:int32,v值:27979;r[i]类型:uint8,r[i]值:230// 4、v类型:int32,v值:65292;r[i]类型:uint8,r[i]值:239// 7、v类型:int32,v值:49;r[i]类型:uint8,r[i]值:49// 8、v类型:int32,v值:50;r[i]类型:uint8,r[i]值:50// 9、v类型:int32,v值:51;r[i]类型:uint8,r[i]值:51// 10、v类型:int32,v值:35797;r[i]类型:uint8,r[i]值:232
单引号包含的内容是字符,其值为int32
(别名rune
)
fmt.Printf("类型:%T,值:%v\n", 'a', 'a')fmt.Printf("类型:%T,值:%v\n", '测', '测')fmt.Printf("类型:%T,值:%v\n", ',', ',')fmt.Printf("类型:%T,值:%v\n", '1', '1')// 类型:int32,值:97// 类型:int32,值:27979// 类型:int32,值:65292// 类型:int32,值:49
上面说过切片可以直接输出,但前提是这个字符串已经存在,如果起始值是数值,或数值型切片,那就必须要使用string()
来解析成字符串再输出。
// 整数fmt.Println(int32(27979)) //输出:27979fmt.Println(string(27979)) //输出:测fmt.Println(string(int32(27979))) //输出:测// 切片u := "测"fmt.Println(u[0:3]) //输出:测fmt.Println([]int32{ 27979}) //输出:[27979]fmt.Println(string([]int32{ 27979})) //输出:测fmt.Println(string([]int32{ 27979, 27979})) //输出:测测fmt.Println(string([]uint8{ 230, 181, 139})) //输出:测fmt.Println(string([]uint8{ 230, 181, 139, 230, 181, 139})) //输出:测测// 整数fmt.Println(uint8(97)) //输出:97fmt.Println(string(97)) //输出:a// 切片u = "a"fmt.Println(u[0:1]) //输出:afmt.Println(string([]uint8{ 97})) //输出:afmt.Println(string([]uint8{ 97, 97})) //输出:aa// 27979// 测// 测// 测// [27979]// 测// 测测// 测// 测测// 97// a// a// a// aa
参考文章:
《》 《》转载地址:http://ttkpi.baihongyu.com/