LeetCode with Go

75 阅读5分钟

Go小白,希望一边刷LeetCode算法顺便掌握Go基本语法,在这里记录遇到的所有愚蠢问题。

105. 从前序与中序遍历序列构造二叉树

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

输入 : preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

解答

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
import (
    "fmt"
)
func buildTree(preorder []int, inorder []int) *TreeNode {
    if len(preorder) == 0 {
        return nil
    }
    root := new(TreeNode)
    root.Val = preorder[0]
    root.Left = nil
    root.Right = nil
    if len(preorder) == 1 {
        // 只有一个节点,不需要继续递归
        return root
    } else {
        // 找到root在inorder中的index
        // var index = sort.SearchInts(inorder, preorder[0])
        var index = slices.Index(inorder, preorder[0])
        fmt.Print(index)
        if index == len(inorder) {
            fmt.Print("越界")
        } 
        root.Left = buildTree(preorder[1: len(inorder[0:index]) + 1], inorder[:index])
        root.Right = buildTree(preorder[len(inorder[0:index]) + 1:], inorder[index + 1:])

        return root
    }
}

遇到的问题1

被题目给出的实例误导了,例子里面给出的左节点的大小为1,就想当然地将递归方法里面的参数写成了

root.Left = buildTree(preorder[1: index + 1], inorder[:index]) 
root.Right = buildTree(preorder[index + 1:], inorder[index + 1:])
遇到的问题2

偷懒不想遍历查找preorder[0]在inorder中的下标,想用

var index = sort.SearchInts(inorder, preorder[0])

发现一直报错数组越界,后面把index打印出来发现是index就找错了。查找资料发现sort.SearchInts()用的是二分查找,也就是传入的数组必须是排好序的。 用slices.Index()或者手动循环查找替代即可。

103. 二叉树的锯齿形层序遍历

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

示例 1:

输入: root = [3,9,20,null,null,15,7]
输出: [[3],[20,9],[15,7]]

示例 2:

输入: root = [1]
输出: [[1]]

示例 3:

输入: root = []
输出: []

解答

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func zigzagLevelOrder(root *TreeNode) [][]int {
    if root == nil{
        return [][]int{}
    }
    parentNum, ChildNum := 1, 0        
    index := 0
    quene := []*TreeNode{root}
    tmp := []int{}
    output := [][]int{[]int{root.Val}}
    flag := false
    for len(quene) > 0 {
        if quene[index].Left != nil {
            quene = append(quene, quene[index].Left)
            ChildNum += 1
            tmp = append(tmp, quene[index].Left.Val)
        }
        if quene[index].Right != nil {
            quene = append(quene, quene[index].Right)
            ChildNum += 1
            tmp = append(tmp, quene[index].Right.Val)
        }
        if index == parentNum -1 {
            if ChildNum == 0 {break}
            if flag {
                output = append(output, tmp)
            } else {
                rev := []int{}
                for _, n := range tmp {
                    rev = append([]int{n}, rev...)
                }
                output = append(output, rev)
            }
            flag = !flag
            tmp = []int{}
            parentNum = ChildNum
            ChildNum = 0
            quene = quene[index+1:]
            index = 0
        } else {
            index += 1
        }

    }
    return output
}

这道题其实就是层序遍历,只是在遍历的时候加上了方向的变化。官方题解有用到双向队列,但是我比较懒就直接把写的层序遍历拿过来改了。 我觉得值得记录的是go的reverse方法。

方法1: 在Go语言中,"..."(三个点)用于创建切片(slice)的变长参数。在这个代码片段中,"..."的作用是将数组中的每个元素追加到切片中。具体来说,...array 中的每个元素作为单独的参数传递给 append 函数,以将其添加到 rev 切片的开头位置。

var rev []string 
for _, n := range array { 
    rev = append([]string{n}, rev...)
}

方法2:

for i,j := 0, len(array)-1 ; i < j ; i, j = i+1, j-1 { 
    array[i],array[j] = array[j], array[i]
}

200. 岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入: grid = [  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]
输出: 1

示例 2:

输入: grid = [  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
输出: 3

深度搜索的方法在这里不记录了,下面是广度搜索的实现。

错误1
// 广度搜索
func numIslands(grid [][]byte) int {
    if grid == nil {
        return 0
    }
    number := 0
    type Point struct {
        point1, point2 int
    }
    quene := []Point{{0, 0}}
    for i := 0; i < len(grid); i++ {
        for j := 0; j < len(grid[0]); j++ {
            if grid[i][j] == '1' {
                number += 1
                // grid[i][j] = '0'
                for len(quene) > 0 {
                    // 开始广度优先
                    point := quene[0]
                    r, c := point.point1, point.point2
                    quene = quene[1:]
                    var newPoint Point
                    if r - 1 >= 0 && grid[r-1][c] == '1' {
                        newPoint = Point{r-1, c}
                         quene = append(quene, newPoint)
                         grid[r-1][c] = '0'
                    }
                    if r + 1 < len(grid) && grid[r+1][c] == '1' {
                        newPoint = Point{r+1, c}
                         quene = append(quene, newPoint)
                         grid[r+1][c] = '0'
                    }
                    if c - 1 >= 0 && grid[r][c-1] == '1' {
                        newPoint = Point{r, c-1}
                         quene = append(quene, newPoint)
                         grid[r][c-1] = '0'
                    }
                    if c + 1 < len(grid[0]) && grid[r][c+1] == '1' {
                        newPoint = Point{r, c+1}
                         quene = append(quene, newPoint)
                         grid[r][c+1] = '0'
                    }
                }
            }
        }
    }
    return number
}

把quene写在了循环的外面,这样的问题是除了[0][0]位置外的‘1’都不会被添加到quene中, 1)[0][0]位置的元素不一定是‘1’,因此不一定需要添加进来 2)后面遇到的其他的首次出现在岛屿中的‘1’元素失去了被添加进quene的机会 修改方法:

// 广度搜索
func numIslands(grid [][]byte) int {
    if grid == nil {
        return 0
    }
    number := 0
    type Point struct {
        point1, point2 int
    }
    for i := 0; i < len(grid); i++ {
        for j := 0; j < len(grid[0]); j++ {
            if grid[i][j] == '1' {
                number += 1
                // grid[i][j] = '0'
                quene := []Point{{i, j}}
                for len(quene) > 0 {
                    // 开始广度优先
                    point := quene[0]
                    r, c := point.point1, point.point2
                    quene = quene[1:]
                    var newPoint Point
                    if r - 1 >= 0 && grid[r-1][c] == '1' {
                        newPoint = Point{r-1, c}
                         quene = append(quene, newPoint)
                         grid[r-1][c] = '0'
                    }
                    if r + 1 < len(grid) && grid[r+1][c] == '1' {
                        newPoint = Point{r+1, c}
                         quene = append(quene, newPoint)
                         grid[r+1][c] = '0'
                    }
                    if c - 1 >= 0 && grid[r][c-1] == '1' {
                        newPoint = Point{r, c-1}
                         quene = append(quene, newPoint)
                         grid[r][c-1] = '0'
                    }
                    if c + 1 < len(grid[0]) && grid[r][c+1] == '1' {
                        newPoint = Point{r, c+1}
                         quene = append(quene, newPoint)
                         grid[r][c+1] = '0'
                    }
                }
            }
        }
    }
    return number
}

值得记录的点: Go语言中没有预先实现好的tuple,如果要实现类似的功能需要自定义struct来完成:

type Point struct {
    point1, point2 int
}

使用并查集的方法可以先学习一下并查集的概念,参考这篇帖子