golang面试-代码编写题1-14

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()
}
posted @ 2022-07-19 18:13  Jeff的技术栈  阅读(55)  评论(0编辑  收藏  举报
回顶部