leetcode 572. 另一个树的子树

152 阅读2分钟

题目链接

以下代码都已提交通过。

解法一

基于另外一道题(判断两树是否相同)的“先序遍历,递归实现”的解法。

先序遍历,双层递归。请看代码。

// 判断subRoot是否为root的子树
// isSubtree是一层递归
func isSubtree(root *TreeNode, subRoot *TreeNode) bool {
    if isSameTree(root, subRoot) {
        return true
    }
    if root != nil {
        if isSubtree(root.Left, subRoot) {
            return true
        }
        if isSubtree(root.Right, subRoot) {
            return true
        }
    }
    return false
}

// 判断两树是否相同
// isSameTree是一层递归
func isSameTree(p *TreeNode, q *TreeNode) bool {
    if p == nil && q == nil {
        return true
    }
    if p != nil && q == nil {
        return false
    }
    if p == nil && q != nil {
        return false
    }
    if p.Val != q.Val {
        return false
    }
    if !isSameTree(p.Left, q.Left) ||
       !isSameTree(p.Right, q.Right) {
        return false
    }
    return true
}

解法二

通过kmp算法判断subRoot树的先序遍历序列是否为root树的先序遍历序列的子序列。为保证序列准确地反映出树结构,空节点也要加入序列中,所以代码中要找到两树中都不存在的两个数分别用于左空节点和右空节点

func isSubtree(root *TreeNode, subRoot *TreeNode) bool {
    if root == nil && subRoot == nil {
        return true
    }
    if root == nil && subRoot != nil {
        return false
    }
    if root != nil && subRoot == nil {
        return false
    }
    // root != nil && subRoot != nil
    
    // 找到两树中都不存在的两个数分别用于左空节点和右空节点。
    m := map[int]struct{}{}
    getNums(root, &m)
    getNums(subRoot, &m)
    nulls := make([]int, 0, 2)
    for i := math.MinInt32; i <= math.MaxInt32; i++ {
        if _, ok := m[i]; !ok {
            nulls = append(nulls, i)
            if len(nulls) >= 2 {
                break
            }
        }
    }
    
    s := getPreOrderArray(root, nil, nulls)
    p := getPreOrderArray(subRoot, nil, nulls)
    return kmp(s, p) != -1
}

func getNums(root *TreeNode, res *map[int]struct{}) {
    if root == nil {
        return
    }
    (*res)[root.Val] = struct{}{}
    getNums(root.Left, res)
    getNums(root.Right, res)
}

func getPreOrderArray(root *TreeNode, res []int, nulls []int) []int {
    res = append(res, root.Val)
    if root.Left != nil {
        res = getPreOrderArray(root.Left, res, nulls)
    } else {
        res = append(res, nulls[0])
    }
    if root.Right != nil {
        res = getPreOrderArray(root.Right, res, nulls)
    } else {
        res = append(res, nulls[1])
    }
    return res
}

func kmp(s, p []int) int {
    var (
        si int
        pi int
        sl = len(s)
        pl = len(p)
        next = getNextArray(p)
    )
    for si < sl {
        if s[si] == p[pi] {
            si++
            pi++
            if pi == pl {
                return si-pl
            }
        } else if pi == 0 {
            si++
        } else {
            pi = next[pi-1]
        }
    }
    return -1
}

func getNextArray(p []int) []int {
    var (
        j int
        i = 1
        l = len(p)
        next = make([]int, l)
    )
    for i < l {
        if p[i] == p[j] {
            j++
            next[i] = j
            i++
        } else if j == 0 {
            next[i] = 0
            i++
        } else {
            j = next[j-1]
        }
    }
    return next
}