切片值为什么会变化?

The value of a slice that be appended to a two-dimension slice, is changed later。 Why does it happen?

The full code is below:

import "sort"
import "fmt"

func combinationSum(candidates []int, target int) [][]int {
    sort.Ints(candidates)
    var ret [][]int
    var curlist []int
    combinationSumRecursive(candidates, target, 0, curlist, &ret)
    fmt.Println("ret", ret)
    return ret
}

func combinationSumRecursive(candidates []int, target int, curCandidateIdx int, curlist []int, ret *[][]int) {
    if target == 0 {
        fmt.Println("put", curlist)
        *ret = append(*ret, curlist)
        return
    }
    for i:=curCandidateIdx;i<len(candidates);i++{
        if candidates[i] > target {
            break
        }
        combinationSumRecursive(candidates, target - candidates[i], i, append(curlist, candidates[i]), ret)
    }
}

INPUT is :

[7,3,2]
18

OUTPUT is below:

put [2 2 2 2 2 2 2 2 2]
put [2 2 2 2 2 2 3 3]
put [2 2 2 2 3 7]
put [2 2 2 3 3 3 3]
put [2 2 7 7]
put [2 3 3 3 7]
put [3 3 3 3 3 3]
ret [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 7 3 3] [2 2 2 2 3 7] [2 2 2 3 3 3 3] [2 2 7 7] [2 3 3 3 7] [3 3 3 3 3 3]]

The second slice in ret is changed. [2 2 2 2 2 2 3 3] was expected.

Thanks to any help.

This is caused by the change of the slice curlist in the append on line combinationSumRecursive(candidates, target - candidates[i], i, append(curlist, candidates[i]), ret).

A solution is to reassign curlist to the appended result before passing it to the next recursive level.

package main

import "sort"
import "fmt"

func combinationSum(candidates []int, target int) [][]int {
    sort.Ints(candidates)
    var ret [][]int
    var curlist []int
    combinationSumRecursive(candidates, target, 0, curlist, &ret)
    fmt.Println("ret", ret)
    return ret
}

func combinationSumRecursive(candidates []int, target int, curCandidateIdx int, curlist []int, ret *[][]int) {
    if target == 0 {
        fmt.Println("put", curlist)
        *ret = append(*ret, curlist)
        return
    }
    for i := curCandidateIdx; i < len(candidates); i++ {
        if candidates[i] > target {
            break
        }
        curlist = append(curlist, candidates[i])
        combinationSumRecursive(candidates, target-candidates[i], i, curlist, ret)
    }
}

func main() {
    combinationSum([]int{7, 3, 2}, 18)
}

This yields:

put [2 2 2 2 2 2 2 2 2]
put [2 2 2 2 2 2 3 3]
put [2 2 2 2 3 7]
put [2 2 2 3 3 3 3]
put [2 2 7 7]
put [2 3 3 3 7]
put [3 3 3 3 3 3]
ret [[2 2 2 2 2 2 2 2 2] [2 2 2 2 2 2 3 3] [2 2 2 2 3 7] [2 2 2 3 3 3 3] [2 2 7 7] [2 3 3 3 7] [3 3 3 3 3 3]]

[EDIT] First read this. That explains that although you see the addresses of the slice headers change the backing array can still be the same after an append.

Then this is an example of what happens in your case. The problem is in your case is it hard to see because of the recursive calls and the re positioning of the current index into curlist.

You're printing the curlist only when target==0 but it keeps changing due to the append(curlist, candidates[i]) in your recursive function. If you try with other candidates, for example : [5,3,2] you will notice that other slices change not only the second.

try making a copy of curlist when the target=0:

if target == 0 {
    fmt.Println("put", curlist)
    newCurlist := make([]int, len(curlist))
    copy(newCurlist, curlist)
    *ret = append(*ret, newCurlist)
    return
}

this should work!