最近在学go语言,为了迅速上手而采用刷leetcode的方法,在这之前刷leetcode使用的语言是java
使用的go语言版本是1.19.2
项目结构和配置
在学go之前,使用java刷leetcode。为了调试方便在自己本地建了一个目录存放代码,然后使用vscode敲代码。由于java每一个class文件都可以包含main方法,调试起来很方便。但是go语言中一个包不能有多个main函数,如果需要多个main函数需要独立建包,很麻烦
大概结构如下:
- Java
题目1.java
题目2.java
题目3.java - GO
题目1包
|---- 题目1.go
题目2包
|---- 题目2.go
题目3包
|---- 题目3.go
这个时候我盯上了go语言中的单元测试模块。单元测试模块只有两个要求
- go文件名以 _test结尾
- 测试函数以Test开头,入参 *testing.T
在vscode里面会自动识别并跳出run test 和debug test的按钮来运行和调试
当然也可以右击函数,选择生成对应的测试函数
go test默认不打印变量,需要在文件>>首选项>>设置>>工作区设置,搜索go后进入对应的setting.json,设置go.testFlags。其中-v表示显示打印信息,-timeout是设置超时,防止永久循环现象。
{
"go.testFlags": [
"-v",
"-timeout=300ms"
],
}
输入转换
leetcode中的输入通常使用json形式,为了转换需要使用go自带的json库 “encoding/json”。以输入2维数组为例,代码如下:
func ConstructInt2DArray(jsonInput string) [][]int {
var str2dArray [][]int
if err := json.Unmarshal([]byte(jsonInput), &str2dArray); err != nil {
log.Fatal(err)
}
return str2dArray
}
对于一些数据结构来说,json的转换还不够,需要进一步的转化,比如链表、树。这一步本身也是训练自己代码能力的步骤。以链表为例
func ConstructListNode(jsonListNode string) *ListNode {
sliceInt := ConstructIntArray(jsonListNode)
head := new(ListNode)
node := head
for _, val := range sliceInt {
node.Next = new(ListNode)
node.Next.Val = val
node = node.Next
}
return head.Next
}
输出转换
为了方便调试,对一些数据结构的输出需要进行一定的处理。这里为链表制作了一个转字符串的函数。
func ListNode2String(root *ListNode) string {
var builder strings.Builder
node := root
builder.WriteString("[")
for {
builder.WriteString(strconv.Itoa(node.Val))
node = node.Next
if node != nil {
builder.WriteString(",")
} else {
break
}
}
builder.WriteString("]")
return builder.String()
}
工具
max、min
不同于java,go语言缺少了很多方便的工具类,比如max函数,go语言只提供了math(float,float)的函数,对于整数并不支持。需要自己处理,以max为例,这里制作了一个任意长度输入的max函数:
func max(nums ...int) int {
max := nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] > max {
max = nums[i]
}
}
return max
}
栈和队列
考虑到go语言在1.8以后支持泛型,为了保持java转过来的习惯,我用泛型写了部分队列、栈的操作。但是leetcode的编译器貌似并不支持泛型,于是放弃。
栈和队列直接使用切片功能实现即可
//栈
stack:=make([]int,0)//栈初始化
stack=append(stack,E)//入栈
E=stack[len(stack)-1]
stack=stack[:len(stack)-1]//出栈
//队列
queue:=make([]int,0)//队列初始化
queue:=append(stack,E)//入队
E=queue[0]
queue=queue[1:]//出队
go的习惯转变
- go没有java这么多的集合类,但是可以用slice和map基本完成leetcode刷题的需求
- go语言的平行赋值可以使得变量的交换非常方便:
a,b=b,a
,不用考虑中间变量。在处理链表的插入更是方便:
//将node插到head后面,同时将node在链表上的位置后移
head.next, node.next, node = node, head.next, node.next
- go可以使用多返回值,比如使用go经典的双返回值:(int,ok),ok表示函数是否成功
- go的if使用:
if d:=dfs(node);d>2
可以在判断的同时提取一个局部变量d - go使用标签配合for循环可以一次break跳出多层循环