golang面试-代码编写题1-14
目录
- 1.代码编写题--统计文本行数-bufio
- 2.代码编写题--多协程收集错误信息-channel
- 3.代码编写题--超时控制,内存泄露
- 4.代码编写题--单例模式
- 5.代码编写题--九九乘法表
- 6.代码编写题--交替打印数字和字⺟
- 7.代码编写题--依次打印猫狗鱼
- 8.代码编写题--判断字符串中字符是否全都不同
- 9.代码编写题--翻转字符串
- 10.代码编写题--判断两个给定的字符串排序后是否⼀致
- 11.代码编写题--字符串替换
- 12.代码编写题--机器人坐标问题
- 13.代码编写题--实现两个channel打印五个随机数。生产消费模型
- 14.代码编写题--补全代码,要求每秒钟调用一次proc并保证程序不退出
- 15.[abc]2[xy]3输出abcabcxyxyxy
- 16.最大在线人数算法
1.代码编写题--统计文本行数-bufio
func demo1() {
file, err := os.Open("./Atest/1.txt")
if err != nil {
return
}
fd := bufio.NewScanner(file)
count := 0
for fd.Scan() {
count++
}
fmt.Println(count)
}
2.代码编写题--多协程收集错误信息-channel
版本1
func demo1(num int) (string, error) {
if num%2 == 0 {
return "", fmt.Errorf("错误,num=%d", num)
}
return fmt.Sprintf("成功,num=%d", num), nil
}
func main() {
wg := sync.WaitGroup{}
errChan := make(chan error)
for i := 0; i < 10; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
_, err := demo1(index)
if err != nil {
errChan <- err
}
}(i)
}
go func() {
wg.Add(1)
for {
errStr, ok := <-errChan
if ok {
fmt.Println(errStr)
} else {
break
}
}
wg.Done()
close(errChan)
}()
time.Sleep(time.Second)
}
版本2
多协程收集错误信息升级,类型断言
func demo1(num int) (string, error) {
if num%2 == 0 {
return "", fmt.Errorf("错误,num=%d", num)
}
return fmt.Sprintf("成功,num=%d", num), nil
}
func main() {
wg := sync.WaitGroup{}
retChan := make(chan interface{})
for i := 0; i < 10; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
data, err := demo1(index)
if err != nil {
retChan <- err
} else {
retChan <- data
}
}(i)
}
go func() {
wg.Add(1)
count := 0
for {
errStr, ok := <-retChan
if ok {
_, ok2 := errStr.(error)
if ok2 {
fmt.Println(errStr)
count++
}
} else {
break
}
if count >= 2 {
break
}
}
wg.Done()
//close(retChan)
}()
time.Sleep(time.Second)
}
3.代码编写题--超时控制,内存泄露
版本1
版本1:会造成内训泄漏,阻塞在done <- struct{}{}
解决:使用缓存chan,因为有缓冲的chan是非阻塞的,直到写满缓冲长度才阻塞。可以适当的缓冲长度调大
done := make(chan struct{},1)
func demo() error {
ctx, _ := context.WithTimeout(context.Background(), time.Second*1)
done := make(chan struct{})
go func() {
//模拟业务
time.Sleep(time.Millisecond * 1200)
done <- struct{}{}
}()
select {
case <-ctx.Done():
return fmt.Errorf("超时")
case <-done:
return nil
}
}
func main() {
for i := 0; i < 100; i++ {
go func() {
demo()
}()
}
for {
time.Sleep(time.Second * 2)
fmt.Println(runtime.NumGoroutine()) //打印当前运行的协程数量
}
}
////////////////
101
101
101
101
版本2
func demo() error {
ctx, _ := context.WithTimeout(context.Background(), time.Second*1)
done := make(chan struct{},1)
go func() {
//模拟业务
time.Sleep(time.Millisecond * 1200)
done <- struct{}{}
}()
select {
case <-ctx.Done():
return fmt.Errorf("超时")
case <-done:
return nil
}
}
func main() {
for i := 0; i < 100; i++ {
go func() {
demo()
}()
}
for {
time.Sleep(time.Second * 2)
fmt.Println(runtime.NumGoroutine()) //打印当前运行的协程数量
}
}
///////////////
1
1
1
4.代码编写题--单例模式
方式1
type Person struct {
Name string
}
var person *Person
var mu sync.Mutex
func NewPerson2(name string) *Person {
if person != nil {
//pass
} else {
mu.Lock()
defer mu.Unlock()
person = &Person{Name: name}
}
return person
}
func main() {
p1 := NewPerson2("hallen1")
p2 := NewPerson2("hallen2")
fmt.Printf("%p\n", p1) // 0xc00008e1e0
fmt.Printf("%p\n", p2) // 0xc00008e1e0
}
方式2:once.Do
var once sync.Once
var person *Person
type Person struct {
Name string
}
func NewPerson2(name string) *Person {
once.Do(func() {
person = new(Person)
person.Name = name
})
return person
}
func main() {
p1 := NewPerson2("hallen1")
p2 := NewPerson2("hallen2")
fmt.Printf("%p\n", p1) // 0xc00008e1e0
fmt.Printf("%p\n", p2) // 0xc00008e1e0
}
5.代码编写题--九九乘法表
func main() {
for i := 1; i <= 9; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%d*%d=%d ", j, i, i*j)
}
fmt.Println(" ")
}
}
///////////
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
6.代码编写题--交替打印数字和字⺟
问题描述:使⽤两个 goroutine 交替打印序列,⼀个 goroutine 打印数字, 另外⼀个goroutine 打印字⺟, 最终效果如下:
12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728
解体思路:
问题很简单,使⽤ channel 来控制打印的进度。使⽤两个 channel ,来分别控制数字和字⺟的打印序列, 数字打印完成后通过 channel 通知字⺟打印, 字⺟打印完成后通知数字打印,然后周⽽复始的⼯作。
func main() {
letter := make(chan bool)
number := make(chan bool)
wg := sync.WaitGroup{}
go func() {
i := 1
for {
select {
case <-number:
fmt.Print(i)
i++
fmt.Print(i)
i++
letter <- true
}
}
}()
wg.Add(1)
go func() {
i := 'A'
for {
select {
case <-letter:
if i >= 'Z' {
wg.Done()
return
}
fmt.Print(string(i))
i++
fmt.Print(string(i))
i++
number <- true
}
}
}()
number <- true
wg.Wait()
}
7.代码编写题--依次打印猫狗鱼
问题描述:3个协程依次打印猫狗鱼
func main() {
catChan := make(chan bool)
dogChan := make(chan bool)
fishChan := make(chan bool)
wg := sync.WaitGroup{}
go func() {
wg.Add(1)
for {
select {
case <-catChan:
fmt.Print("猫")
dogChan <- true
}
}
}()
go func() {
wg.Add(1)
for {
select {
case <-dogChan:
fmt.Print("狗")
fishChan <- true
}
}
}()
go func() {
wg.Add(1)
for {
select {
case <-fishChan:
fmt.Print("鱼")
catChan <- true
}
}
}()
catChan <- true
wg.Wait()
}
8.代码编写题--判断字符串中字符是否全都不同
问题描述:
请实现⼀个算法,确定⼀个字符串的所有字符【是否全都不同】。这⾥我们要求【不允许使⽤额外的存储结构】。给定⼀个string,请返回⼀个bool值,true代表所有字符全都不同,false代表存在相同的字符。保证字符串中的字符为【ASCII字符】。字符串的⻓度⼩于等于【3000】。
解题思路:
这⾥有⼏个重点,第⼀个是ASCII字符, ASCII字符字符⼀共有256个,其中128个是常⽤字符,可以在键盘上输⼊。128之后的是键盘上⽆法找到的。
然后是全部不同,也就是字符串中的字符没有重复的,再次,不准使⽤额外的储存结构,且字符串⼩于等于3000。
如果允许其他额外储存结构,这个题⽬很好做。如果不允许的话,可以使⽤golang内置的⽅式实现。
//判断s字符串有几个不重复的v子串
strings.Count(s, string(v))
func isUniqueString(s string) bool {
for _, v := range s {
if v > 127 {
return false
}
if strings.Count(s, string(v)) > 1 {
return false
}
}
return true
}
// strings.Index(s,string(v)) 判断字符串v在s字符串出现的位置,不存在返回-1
func isUniqueString2(s string) bool {
for k,v := range s {
if v > 127 {
return false
}
if strings.Index(s,string(v)) != k {
return false
}
}
return true
}
9.代码编写题--翻转字符串
问题描述:
翻转给定字符串,abc-->cba
解题思路:
以字符串长度1/2为轴,前后反转赋值
func reverString(s string) string {
str := []rune(s)
l := len(str)
for i := 0; i < l/2; i++ {
str[i], str[l-1-i] = str[l-1-i], str[i]
}
return string(str)
}
10.代码编写题--判断两个给定的字符串排序后是否⼀致
问题描述:
给定两个字符串,请编写程序,确定其中⼀个字符串的字符重新排列后,能否变成另⼀个字符串。
这⾥规定【⼤⼩写为不同字符】,且考虑字符串重点空格。给定⼀个string s1和⼀个string s2,请返回⼀个bool,代表两串是否重新排列后可相同。
解决思路:
循环遍历s1,strings.Count数量在s2中是否相等
func isRegroup(s1, s2 string) bool {
for _, v := range s1 {
if strings.Count(s1, string(v)) != strings.Count(s2, string(v)) {
return false
}
}
return true
}
func main() {
s1 := "abc"
s2 := "cba"
boo := isRegroup(s1, s2)
fmt.Println(boo) //true
}
11.代码编写题--字符串替换
func replaceBlank(s, oldStr, newStr string) string {
return strings.Replace(s, oldStr, newStr, -1)
}
func main() {
s := "abcdeffff"
res := replaceBlank(s, "f", "k")
fmt.Println(res) //abcdekkkk
}
12.代码编写题--机器人坐标问题
问题描述:
有⼀个机器⼈,给⼀串指令,L左转 R右转,F前进⼀步,B后退⼀步,问最后机器⼈的坐标,最开始,机器⼈位于 0 0,⽅向为正Y。
可以输⼊重复指令n : ⽐如 R2(LF) 这个等于指令 RLFLF。
问最后机器⼈的坐标是多少?
//面朝方向: 1前 2右 3后 4左
// (0,0,1),x,y表示坐标,z表示面朝方向。支持的指令:L左转 R右转,F前进⼀步,B后退⼀步
func move(t [3]int, cmd string) [3]int {
for _, v := range cmd {
switch string(v) {
case "L":
//向左转
if t[2] == 1 {
t[2] = 4
} else {
t[2]--
}
case "R":
//向右转
if t[2] == 4 {
t[2] = 1
} else {
t[2]++
}
case "F":
//前进,看面朝方向
if t[2] == 1 {
//面朝前后改变y轴
t[1]++
} else if t[2] == 3 {
t[1]--
} else if t[2] == 2 {
//面朝前后改变x轴
t[0]++
} else if t[2] == 4 {
t[0]--
}
case "B":
//后退,看面朝方向,面朝前后改变y轴
if t[2] == 1 {
//面朝前后改变y轴
t[1]--
} else if t[2] == 3 {
t[1]++
} else if t[2] == 2 {
//面朝前后改变x轴
t[0]--
} else if t[2] == 4 {
t[0]++
}
}
}
return t
}
func main() {
t := [3]int{0, 0, 1} //初始值:机器人在原点,面朝前方
re := move(t, "FFFFRFFF")
fmt.Println(re)
}
13.代码编写题--实现两个channel打印五个随机数。生产消费模型
func main() {
out := make(chan int, 1)
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
defer close(out)
for i := 0; i < 5; i++ {
out <- rand.Intn(10)
}
}()
go func() {
defer wg.Done()
for i := range out {
fmt.Println(i)
}
}()
wg.Wait()
}
14.代码编写题--补全代码,要求每秒钟调用一次proc并保证程序不退出
package main
func main() {
go func() {
// 1 在这⾥需要你写算法
// 2 要求每秒钟调⽤⼀次proc函数
// 3 要求程序不能退出
}()
select {}
}
func proc() {
panic("ok")
}
解析:
题⽬主要考察了两个知识点:
1. 定时执⾏执⾏任务
2. 捕获 panic 错误
题⽬中要求每秒钟执⾏⼀次,⾸先想到的就是 time.Ticker 对象,该函数可每秒钟往chan 中放⼀个Time ,正好符合我们的要求。
在 golang 中捕获 panic ⼀般会⽤到 recover() 函数。
编写代码:
func main() {
go func() {
// 1 在这⾥需要你写算法
// 2 要求每秒钟调⽤⼀次proc函数
// 3 要求程序不能退出
t := time.NewTicker(1 * time.Second)
for {
select {
case <-t.C:
go func() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
proc()
}()
}
}
}()
select {}
}
func proc() {
panic("ok")
}
15.[abc]2[xy]3输出abcabcxyxyxy
/*
题目:
[abc]2[xy]3输出abcabcxyxyxy
算法原理:
*/
func demo(st string) {
var endStr, x string
t := false
for _, v := range st {
if v == 91 {
t = true
continue
} else if v == 93 {
t = false
continue
} else if v >= 48 && v <= 57 {
a, _ := strconv.Atoi(string(v))
endStr += strings.Repeat(x, a)
x = ""
continue
}
if t {
x += string(v)
} else {
endStr += string(v)
}
}
fmt.Println(endStr)
}
func main() {
//in := "[qwe]2abc[d]3"
in := "[abc]2[xy]3"
demo(in)
}
python:
def main(st):
endStr = ""
t = False
x = ""
for i in st:
if ord(i) == 91:
t = True
continue
elif ord(i) == 93:
t = False
continue
elif ord(i) >= 48 and ord(i) <= 57:
endStr += (x * int(i))
x = ""
continue
if t:
x += i
else:
endStr += i
return endStr
if __name__ == '__main__':
st = "[qwe]2abc[d]3"
# st="[abc]2[xy]3"
# st="[]0"
print(main(st))
16.最大在线人数算法
/*
// start,end 分别代表开始面试时间戳,结束面试时间戳。面试时间为[start,end]
// 计算最大在线人数以及持续的时间段。如果有多个时间段,返回其中一个即可
// 示例:[[100,200],[900,1000],[150,300]]
// 输出: 2,150,200
// 解释: 最大同时在线人数2 人,持续时间为[150,200]
*/
/*
算法原理:
1.轮训每一个人的开始时间是否在其他人的开始时间至结束时间段内。是则在线人数+1
2.取出最大的在线人数
3.最大人数开始时间段取:最大的开始时间
4.最大人数结束时间段:取最小的结束时间段。。。范围重合时间取值
*/
func Demo() {
lis := [][]int{{100, 200}, {150, 300}, {100, 1000}, {150, 300}, {150, 210}}
//lis := [][]int{{100, 200}, {150, 300}, {160, 190}}
maxCount := 0 //在线人数
reSta := 0 //初始化为0,开始时间
reEnd := 1000 //初始化为:最后一个人的结束时间
for k := range lis {
count := 1
st := lis[k][0]
en := lis[k][1]
sta := 0
end := 0
for i := 0; i < len(lis); i++ {
if i == k {
continue
}
if st <= lis[i][0] && en >= lis[i][0] {
count += 1
sta = lis[i][0]
if lis[i][1] >= en {
end = en
} else {
end = lis[i][1]
}
}
}
if count > maxCount {
maxCount = count
}
if sta > reSta {
reSta = sta
}
if end < reEnd {
reEnd = end
}
}
fmt.Println(maxCount)
fmt.Println(reSta)
fmt.Println(reEnd)
}
func main() {
Demo()
}
选择了IT,必定终身学习