1 判断字符串中字符是否全都不同
问题描述
请实现一个算法,确定一个字符串的所有字符【是否全都不同】。这里我们要
求【不允许使用额外的存储结构】。给定一个string,请返回一个bool
值,true代表所有字符全都不同,false代表存在相同的字符。保证字符串中的
字符为【ASCII字符】。字符串的长度小于等于【3000】。
解题思路
这里有几个重点,第一个是ASCII字符,ASCII字符字符一共有256个,其中128
个是常用字符,可以在键盘上输入。128之后的是键盘上无法找到的。
然后是全部不同,也就是字符串中的字符没有重复的,再次,不准使用额外的
储存结构,且字符串小于等于3000。
如果允许其他额外储存结构,这个题目很好做。如果不允许的话,可以使用
golang内置的方式实现。
源码参考
通过strings.Count函数判断:
Go
func isUniqueString(s string) bool {
if strings.Count(s, "") > 3000 {
return false
}
for _, v := range s {
if v > 127 {
return false
}
if strings.Count(s, string(v)) > 1 {
return false
}
}
return true
}
Go
func isUniqueString2(s string) bool {
if strings.Count(s, "") > 3000 {
return false
}
for k, v := range s {
if v > 127 {
return false
}
if strings.Index(s, string(v)) != k {
return false
}
}
return true
}
源码解析
以上两种方法都可以实现这个算法。
第一个方法使用的是golang内置方法strings.Count,可以用来判断在一个字符
串中包含的另外一个字符串的数量。
第二个方法使用的是golang内置方法strings.Index和strings.LastIndex,用来判
断指定字符串在另外一个字符串的索引未知,分别是第一次发现位置和最后发
现位置。
2 翻转字符串
问题描述
请实现一个算法,在不使用【额外数据结构和储存空间】的情况下,翻转一个
给定的字符串(可以使用单个过程变量)。
给定一个string,请返回一个string,为翻转后的字符串。保证字符串的长度
小于等于5000。
解题思路
翻转字符串其实是将一个字符串以中间字符为轴,前后翻转,即将str[len]赋
值给str[0],将str[0]赋值str[len]。
源码参考
Go
func reverseString(s string) (string, bool) {
str := []rune(s)
l := len(str)
if l > 5000 {
return s, false
}
for i := 0; i < l/2; i++ {
str[i], str[l-1-i] = str[l-1-i], str[i]
}
return string(str), true
}
源码解析
以字符串长度的1/2为轴,前后赋值
3 判断两个给定的字符串排序后是否一致
问题描述
给定两个字符串,请编写程序,确定其中一个字符串的字符重新排列后,能否
变成另一个字符串。这里规定【大小写为不同字符】,且考虑字符串重点空
格。给定一个strings1和一个strings2,请返回一个bool,代表两串是否重
新排列后可相同。保证两串的长度都小于等于5000。
解题思路
首先要保证字符串长度小于5000。之后只需要一次循环遍历s1中的字符在s2
是否都存在即可。
源码参考
Go
func isRegroup(s1, s2 string) bool {
sl1 := len([]rune(s1))
sl2 := len([]rune(s2))
if sl1 > 5000 || sl2 > 5000 || sl1 != sl2 {
return false
}
for _, v := range s1 {
if strings.Count(s1, string(v)) != strings.Count(s2, string(v)) {
return false
}
}
return true
}
源码解析
这里还是使用golang内置方法strings.Count来判断字符是否一致。
4 字符串替换问题
问题描述
请编写一个方法,将字符串中的空格全部替换为"%20"。假定该字符串有足
够的空间存放新增的字符,并且知道字符串的真实长度(小于等于1000),同时
保证字符串由【大小写的英文字母组成】。给定一个string为原始的串,返
回替换后的string。
解题思路
两个问题,第一个是只能是英文字母,第二个是替换空格。
源码参考
Go
func replaceBlank(s string) (string, bool) {
if len([]rune(s)) > 1000 {
return s, false
}
for _, v := range s {
if string(v) != " " && unicode.IsLetter(v) == false {
return s, false
}
}
//return strings.ReplaceAll(s, "", "##"), true
res := strings.Replace(s, " ", "%20", -1)
return res, true
}
源码解析
这里使用了golang内置方法unicode.IsLetter判断字符是否是字母,之后使用
strings.Replace来替换空格。
5 机器人坐标问题
问题描述
有一个机器人,给一串指令,L左转R右转,F前进一步,B后退一步,问最
后机器人的坐标,最开始,机器人位于00,方向为正Y。可以输入重复指令
n:比如R2(LF)这个等于指令RLFLF。问最后机器人的坐标是多少?
解题思路
这里的一个难点是解析重复指令。主要指令解析成功,计算坐标就简单了。
源码参考
packagemain
import(
"unicode"
)
const(
Left=iota
Top
Right
Bottom
)
funcmain(){
println(move("R2(LF)",0,0,Top))
}
funcmove(cmdstring,x0int,y0int,z0int)(x,y,zint){
x,y,z=x0,y0,z0
repeat:=0
repeatCmd:=""
for_,s:=rangecmd{
switch{
caseunicode.IsNumber(s):
repeat=repeat*10+(int(s)-'0')
cases==')':
fori:=0;i<repeat;i++{
x,y,z=move(repeatCmd,x,y,z)
}
repeat=0
repeatCmd=""
caserepeat>0&&s!='('&&s!=')':
repeatCmd=repeatCmd+string(s)
cases=='L':
z=(z+1)%4
cases=='R':
z=(z-1+4)%4
cases=='F':
switch{
casez==Left||z==Right:
x=x-z+1
casez==Top||z==Bottom:
y=y-z+2
}
cases=='B':
switch{
casez==Left||z==Right:
x=x+z-1
casez==Top||z==Bottom:
y=y+z-2
}
}
}
return
}
源码解析
这里使用三个值表示机器人当前的状况,分别是:x表示x坐标,y表示y坐
标,z表示当前方向。L、R命令会改变值z,F、B命令会改变值x、y。值
x、y的改变还受当前的z值影响。
如果是重复指令,那么将重复次数和重复的指令存起来递归调用即可。
常见语法题目一
1、下面代码能运行吗?为什么。
typeParammap[string]interface{}
typeShowstruct{
Param
}
funcmain1(){
s:=new(Show)
s.Param["RMB"]=10000
}
解析
共发现两个问题:
1.main函数不能加数字。
2.new关键字无法初始化Show结构体中的Param属性,所以直接
对s.Param操作会出错。
2、请说出下面代码存在什么问题。
typestudentstruct{
Namestring
}
funczhoujielun(vinterface{}){
switchmsg:=v.(type){
case*student,student:
msg.Name
}
}
解析:
golang中有规定,switchtype的caseT1,类型列表只有一个,那么v:=m.(type)
中的v的类型就是T1类型。
如果是caseT1,T2,类型列表中有多个,那v的类型还是多对应接口的类型,也
就是m的类型。
所以这里msg的类型还是interface{},所以他没有Name这个字段,编译阶段就
会报错。具体解释见:https://golang.org/ref/spec#Type_switches
3、写出打印的结果。
typePeoplestruct{
namestring`json:"name"`
}
funcmain(){
js:=`{
"name":"11"
}`
varpPeople
err:=json.Unmarshal([]byte(js),&p)
iferr!=nil{
fmt.Println("err:",err)
return
}
fmt.Println("people:",p)
}
解析:
按照golang的语法,小写开头的方法、属性或struct是私有的,同样,在
json解码或转码的时候也无法上线私有属性的转换。
题目中是无法正常得到People的name值的。而且,私有属性name也不应该加
json的标签
4、下面的代码是有问题的,请说明原因。
typePeoplestruct{
Namestring
}
func(p*People)String()string{
returnfmt.Sprintf("print:%v",p)
}
funcmain(){
p:=&People{}
p.String()
}
解析:
在golang中String()string方法实际上是实现了String的接口的,该接口定义
在fmt/print.go中:
typeStringerinterface{
String()string
}
在使用fmt包中的打印方法时,如果类型实现了这个接口,会直接调用。而题
目中打印p的时候会直接调用p实现的String()方法,然后就产生了循环调
用。