腾讯互娱面经详解

2024年 5月 11日 56.3k 0

先来唠唠

腾讯互娱面经详解-1图片

今天刷脉脉的时候, 发现百度副总裁璩静一个人竟然占了前三的两个热榜, 对于她的离职你怎么看?

言归正传, 本文的重点还是分享面经干货

今天分享的是一位朋友在腾讯互娱的面经, 他本人目前已经是收到offer了, 让我们来看看这个难度如何:

腾讯互娱面经详解-2图片

面试题详解

Go接口

接口在Golang中扮演着连接不同类型之间的桥梁,它定义了一组方法的集合,而不关心具体的实现。接口的作用主要体现在以下几个方面:

多态性:

接口允许不同的类型实现相同的方法,从而实现多态性。这意味着我们可以使用接口类型来处理不同的对象,而不需要关心具体的类型。

package main

import "fmt"

type Animal interface {
 Sound() string
}

type Dog struct{}

func (d Dog) Sound() string {
 return "Woof!"
}

type Cat struct{}

func (c Cat) Sound() string {
 return "Meow!"
}

func main() {
 animals := []Animal{Dog{}, Cat{}}

 for _, animal := range animals {
  fmt.Println(animal.Sound())
 }
}

在上面的示例中,我们定义了一个Animal接口,它包含了一个Sound()方法。然后,我们实现了Dog和Cat两个结构体,分别实现了Sound()方法。通过将Dog和Cat类型赋值给Animal接口类型,我们可以在循环中调用Sound()方法,而不需要关心具体的类型。这就体现了接口的多态性,不同的类型可以实现相同的接口方法。

解耦合:

接口可以将抽象与实现分离,降低代码之间的耦合度。通过定义接口,我们可以将实现细节隐藏起来,只暴露必要的方法,从而提高代码的可维护性和可读性。

package main

import "fmt"

type Printer interface {
 Print(string)
}

type ConsolePrinter struct{}

func (cp ConsolePrinter) Print(message string) {
 fmt.Println(message)
}

type FilePrinter struct{}

func (fp FilePrinter) Print(message string) {
 // 将消息写入文件
 fmt.Println("Writing message to file:", message)
}

func main() {
 printer := ConsolePrinter{}
 printer.Print("Hello, World!")

 printer = FilePrinter{}
 printer.Print("Hello, World!")
}

在上面的示例中,我们定义了一个Printer接口,它包含了一个Print()方法。然后,我们实现了ConsolePrinter和FilePrinter两个结构体,分别实现了Print()方法。通过将不同的结构体赋值给Printer接口类型的变量,我们可以在主函数中调用Print()方法,而不需要关心具体的实现。这样,我们可以根据需要轻松地切换不同的打印方式,实现了解耦合。

可扩展性:

package main

import "fmt"

type Shape interface {
 Area() float64
}

type Rectangle struct {
 Width  float64
 Height float64
}

func (r Rectangle) Area() float64 {
 return r.Width * r.Height
}

type Circle struct {
 Radius float64
}

func (c Circle) Area() float64 {
 return 3.14 * c.Radius * c.Radius
}

func main() {
 shapes := []Shape{Rectangle{Width: 5, Height: 10}, Circle{Radius: 3}}

 for _, shape := range shapes {
  fmt.Println("Area:", shape.Area())
 }
}

在上面的示例中,我们定义了一个Shape接口,它包含了一个Area()方法。然后,我们实现了Rectangle和Circle两个结构体,分别实现了Area()方法。通过将不同的结构体赋值给Shape接口类型的切片,我们可以在循环中调用Area()方法,而不需要关心具体的类型。这样,当我们需要添加新的形状时,只需要实现Shape接口的Area()方法即可,而不需要修改已有的代码。这就实现了代码的可扩展性。

接口的应用场景

  • API设计:接口在API设计中起到了至关重要的作用。通过定义接口,我们可以规范API的输入和输出,提高代码的可读性和可维护性。
  • 单元测试:接口在单元测试中也扮演着重要的角色。通过使用接口,我们可以轻松地替换被测试对象的实现,从而实现对被测代码的独立测试。
  • 插件系统:接口可以用于实现插件系统,通过定义一组接口,不同的插件可以实现这些接口,并在程序运行时动态加载和使用插件。
  • 依赖注入:接口在依赖注入中也有广泛的应用。通过定义接口,我们可以将依赖对象的创建和管理交给外部容器,从而实现松耦合的代码结构。
  • 空结构体的用途

    不包含任何字段的结构体,就叫做空结构体。

    空结构体的特点:

  • 零内存占用
  • 地址都相同
  • 无状态
  • 空结构体的使用场景

    • 实现set集合

    在 Go 语言中,虽然没有内置 Set 集合类型,但是我们可以利用 map 类型来实现一个 Set 集合。由于 map 的 key 具有唯一性,我们可以将元素存储为 key,而 value 没有实际作用,为了节省内存,我们可以使用空结构体作为 value 的值。

    package main
    
    import "fmt"
    
    type Set[K comparable] map[K]struct{}
    
    func (s Set[K]) Add(val K) {
       s[val] = struct{}{}
    }
    func (s Set[K]) Remove(val K) {
       delete(s, val)
    }
    
    func (s Set[K]) Contains(val K) bool {
       _, ok := s[val]
       return ok
    }
    
    func main() {
       set := Set[string]{}
       set.Add("程序员")
       fmt.Println(set.Contains("程序员")) // true
       set.Remove("程序员")
       fmt.Println(set.Contains("程序员")) // false
    }
    • 用于通道信号

    空结构体常用于 Goroutine 之间的信号传递,尤其是不关心通道中传递的具体数据,只需要一个触发信号时。例如,我们可以使用空结构体通道来通知一个 Goroutine 停止工作:

    package main  

    import (
    "fmt"
    "time"
    )

    func main() {
    quit := make(chan struct{})
    go func() {
    // 模拟工作
    fmt.Println("工作中...")
    time.Sleep(3 * time.Second)
    // 关闭退出信号
    close(quit)
    }()

    // 阻塞,等待退出信号被关闭
    操作符带索引的列

  • range:只检索给定范围的行,使用一个索引来选择行。一般使用between、>、7->19->26,发现26比23大,就回到19
  • 再用第1层连接19->22->26,发现比23大,那么就插入到26之前,22之后
  • 上面这张图就是跳表的初步原理,但一个元素插入链表后,应该拥有几层连接呢?跳表在这块的实现方式是随机的,也就是23这个元素插入后,随机出一个数,比如这个数是3,那么23就会有如下连接:

    • 第3层head->23->end
    • 第2层19->23->26
    • 第1层22->23->26

    下面这张图展示了如何形成一个跳表

    腾讯互娱面经详解-3图片

    在上述跳表中查找/插入23的过程为:

    腾讯互娱面经详解-4图片

    总结一下跳表原理:

    • 每个跳表都必须设定一个最大的连接层数MaxLevel
    • 第一层连接会连接到表中的每个元素
    • 插入一个元素会随机生成一个连接层数值[1, MaxLevel]之间,根据这个值跳表会给这元素建立N个连接
    • 插入某个元素的时候先从最高层开始,当跳到比目标值大的元素后,回退到上一个元素,用该元素的下一层连接进行遍历,周而复始直到第一层连接,最终在第一层连接中找到合适的位置

    使用场景:

    • 对有序数据进行排序,例如新闻排行榜或游戏排行榜。
    • 对数据进行分组,例如将所有评分在3.0 到4.0 之间的电影分为一组。
    • 对数据进行去重,例如将所有重复的单词从文本中删除。

    本文转载自微信公众号「王中阳Go」,作者「王中阳Go」,可以通过以下二维码关注。

    腾讯互娱面经详解-5

    转载本文请联系「王中阳Go」公众号。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论