LeetCode问题Path Sum II:递归解决方案错误

时间:2020-07-19 12:12:31

标签: go recursion path tree

我已经为golang中的question提交了以下解决方案,但对于基本情况失败了。我无法弄清楚为什么会失败。

var answer[][]int

func hasPathSum(root *TreeNode, sum int, path []int){
    if root == nil {
        return
    }
    newPath := append(path, root.Val)
    sum = sum - root.Val
    if root.Left == nil && root.Right == nil && sum == 0 {
        answer = append(answer, newPath)
        fmt.Println(answer)
        return
    }
    if root.Left != nil {
        hasPathSum(root.Left, sum, newPath)
    }
    if root.Right != nil {
        hasPathSum(root.Right, sum, newPath)
    }
    
}

func pathSum(root *TreeNode, sum int) [][]int {
    
    var path []int
    answer = [][]int{}
    hasPathSum(root, sum, path)
    return answer
}

当我避免声明newPath时,它将通过基本检查。像这样:

var answer[][]int

func hasPathSum(root *TreeNode, sum int, path []int){
    if root == nil {
        return
    }

    sum = sum - root.Val
    if root.Left == nil && root.Right == nil && sum == 0 {
        answer = append(answer, append(path, root.Val))
        fmt.Println(answer)
        return
    }
    if root.Left != nil {
        hasPathSum(root.Left, sum, append(path, root.Val))
    }
    if root.Right != nil {
        hasPathSum(root.Right, sum, append(path, root.Val))
    }
    
}

func pathSum(root *TreeNode, sum int) [][]int {
    
    var path []int
    answer = [][]int{}
    hasPathSum(root, sum, path)
    return answer
}

我无法弄清楚两种解决方案之间的区别是什么。从递归的角度来看,这两种解决方案是相同的。此外,C ++中的similar solution通过了所有检查。

2 个答案:

答案 0 :(得分:3)

发生此问题是因为切片引用了基础数组,并且如果有空间,index: ( 2 0 ) 不会重新分配新数组。参见2

这意味着当您append时,新切片有时会与append(path, root.Val)共享后备阵列。可能是个问题,例如:

path

在这里,两个分支都可能使用相同的后备数组。这是一个问题,因为在执行第一个if root.Left != nil { hasPathSum(root.Left, sum, append(path, root.Val)) } if root.Right != nil { hasPathSum(root.Right, sum, append(path, root.Val)) } 时,它可能会向hasPathSum添加一个分片,但是该分片的基础数组仍可以在对answer的第二次调用中使用更改其内容。

两个版本的代码都有相同的问题,但是因为第二个版本不太可能引起问题,因为如果hasPathSum需要重新分配,那么您将在append(path, root.Val)的两个分支中获得两个不同的副本。 。这意味着该错误将以较低的频率发生。

答案 1 :(得分:0)

我不确定# # example Makefile based on OP version # build 2 sets of obj with- or without feature flags # # $(shell touch foo.cu) # regular, feature TARGET_REG := reg-name TARGET_FTR := ftr-name DIR_REG := objreg DIR_FTR := objftr # $(shell mkdir -p $(DIR_REG) $(DIR_FTR) CU_SRC := $(wildcard *.cu) CU_OBJ := $(CU_SRC:%.cu=%-cu.o) # $(info CU_SRC "$(CU_SRC)") # $(info CU_OBJ "$(CU_OBJ)") OBJ_REG := $(addprefix $(DIR_REG)/, $(CU_OBJ)) OBJ_FTR := $(addprefix $(DIR_FTR)/, $(CU_OBJ)) # $(info OBJ_REG "$(OBJ_REG)") # $(info OBJ_FTR "$(OBJ_FTR)") # added feature flags: FTR_FLAGS := -abc .PHONY: all clean all: $(TARGET_REG) $(TARGET_FTR) $(TARGET_REG): $(OBJ_REG) @echo -e " link $@, OBJ $^\n" $(TARGET_FTR): $(OBJ_FTR) @echo -e " link $@, OBJ $^\n" clean: $(RM) foo* $(OBJ_REG) $(OBJ_FTR) $(OBJ_FTR): CU_STUFF += $(FTR_FLAGS) $(DIR_REG)/%-cu.o: %.cu @echo build $< to $@, CU_STUFF \"$(CU_STUFF)\" $(DIR_FTR)/%-cu.o: %.cu @echo build $< to $@, CU_STUFF \"$(CU_STUFF)\" ,您可能只需要回答fmt.Println(answer)

这将通过:

return

这是LeetCode的Java解决方案,带有注释:

func pathSum(root *TreeNode, sum int) [][]int {
    var paths [][]int

    if root == nil {
        return paths
    }

    if root.Left == nil && root.Right == nil {
        if sum == root.Val {
            return append(paths, []int{ root.Val })
        }

        return paths
    }

    for _, path := range pathSum(root.Left, sum - root.Val) {
        paths = append(paths, append([]int{ root.Val}, path... ))
    }

    for _, path := range pathSum(root.Right, sum - root.Val) {
        paths = append(paths, append([]int{ root.Val}, path... ))
    }

    return paths
}

参考文献

相关问题