Golang面试考题记录 ━━ 最长公共前缀,字符串就是切片,复习[]byte、[]rune、[]uint8、[]int32和单引号

===问:

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。

示例 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取值的类型为uint8(别名byte)。在有中文情况下,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))         //输出:27979
fmt.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))  //输出:97
fmt.Println(string(97)) //输出:a
// 切片
u = "a"
fmt.Println(u[0:1])                  //输出:a
fmt.Println(string([]uint8{97}))     //输出:a
fmt.Println(string([]uint8{97, 97})) //输出:aa
// 27979
// 测
// 测
// 测
// [27979]
// 测
// 测测
// 测
// 测测
// 97
// a
// a
// a
// aa

参考文章:
Golang学习日志 ━━ 一图一代码看懂range、byte、rune、uint8、int32
Go语言圣经-字节切片与字符串

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值