Go算法

(23)Go递归求二叉树各类路径问题2

2019-05-14  本文已影响0人  哥斯拉啊啊啊哦

继上篇《(22)Go递归求二叉树各类路径问题1》https://www.jianshu.com/p/7b85290659a6

问题4:求二叉树指定路径 //
方法1:从上往下添加路径
测试结果速度100,内存6.67,速度可以但太耗费内存,方法2更加快
func pathSum(root *TreeNode, sum int) [][]int {
    res := [][]int{}
    arrs := []int{}

    var f func(t *TreeNode, sum int, arr []int)
    f = func(t *TreeNode, sum int, arr []int) {
        if t == nil {
            return
        }

        arr = append(arr, t.Val)
        if t.Val == sum && t.Left == nil && t.Right == nil {
            res = append(res, arr)
            return
        }

        if t.Left != nil {
            // 做一次复制
            buf := append([]int{}, arr...)
            f(t.Left, sum-t.Val, buf)
        }

        if t.Right != nil {
            // 做一次复制
            buf := append([]int{}, arr...)
            f(t.Right, sum-t.Val, buf)
        }
    }

    f(root, sum, arrs)
    return res
}

方法1提交leetcode,通过

方法2:从下往上添加路径,leetcode上优秀解答,作者未知,思路很棒
// 做了一点小修改
func pathSum2(root *TreeNode, sum int) [][]int {
    // 递归终止条件
    if root == nil {
        return [][]int{}
    }

    // 递归过程
    if sum == root.Val && root.Left == nil && root.Right == nil {
        return [][]int{[]int{sum}}
    }

    sum -= root.Val
    left, right := [][]int{}, [][]int{}

    if root.Left != nil {
        left = pathSum2(root.Left, sum)
    }
    if root.Right != nil {
        right = pathSum2(root.Right, sum)
    }
    total := append(left, right...)

    // 精髓1:只要最终左右有1个成立,就会执行这一步,一直往上加,
    // 相比方法1少了很多添加路径和复制的操作
    // 如果这一步没执行,说明左右都没有成立的,返回的tatal是空的
    if len(total) > 0 {
        rootInt := []int{root.Val}
        for i := range total {
            total[i] = append(rootInt, total[i]...)
        }
    }
    return total
}

方法2的测试结果

问题5:找特定子路径 //
思路如下图示:
// 注意2个函数的区别,1个包含根节点,一个不必要包含根节点
// 在root为根节点的二叉树中,寻找sum的路径,返回路径个数
func pathSum(root *TreeNode, sum int) int {
    // 递归终止条件
    if root == nil {
        return 0
    }

    // 递归过程
    // res:符合条件的路径数量
    res := findPath(root, sum)
    res += pathSum(root.Left, sum) + pathSum(root.Right, sum)
    return res
}

// 在以t为根节点的二叉树中,寻找包含t的路径,和为sum的路径总数
// 返回路径个数(和上面对比,1个路径不包含根节点,一个包含根节点)
func findPath(t *TreeNode, sum int) int {
    // 递归终止条件
    if t == nil {
        return 0
    }

    // 递归过程
    // res:符合条件的路径数量
    res := 0
    if sum == t.Val {
        res++
    }

    res += findPath(t.Left, sum-t.Val) + findPath(t.Right, sum-t.Val)
    return res
}

提交leetcode,通过

问题6:求两点近公共祖先 //
思路:这个问题的难点在于弄清公共祖先的情况:
给定的2个点必须同时满足小于根节点,或者大于根节点,不然该根节点就是这2节点的最近公共祖先
弄明白这情况代码就好写很多
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    // 递归终止条件
    if root == nil {
        return nil
    }

    // 递归过程
    if p.Val < root.Val && q.Val < root.Val {
        return lowestCommonAncestor(root.Left, p, q)
    } else if p.Val > root.Val && q.Val > root.Val {
        return lowestCommonAncestor(root.Right, p, q)
    }

    // 这里有个小bug,如果p, q不存在树中且最后在叶子节点达到这一步,
    // 那返回这个叶子节点,显然叶子节点是不可能成为公共祖先的,
    // 严谨一点要再去判断下p,q是否存在树中
    return root
}

提交leetcode,通过

有bug欢迎指出

上一篇下一篇

猜你喜欢

热点阅读