Loading

go 二维切片append时的问题(深拷贝相关/go实现回溯法问题)

我在leetcode做的时候,用go去实现了一个回溯算法
216数组的和

func combinationSum3(k int, n int) [][]int {
	res := make([][]int, 0)
	path := make([]int, 0)
	var backtracting func(int, int, int, int)
	backtracting = func(n, k, start, target int) {
		if target < 0 || len(path) > k {
			return
		}
		if target == 0 && len(path) == k {
			//注意此处
			res = append(res, path)
			//
			return
		}
		for i := start; i <= 9; i++ {
			path = append(path, i)
			backtracting(n, k, i+1, target-i)
			path = path[:len(path)-1]
		}
	}
	backtracting(n, k, 1, n)
	return res
}

当输入为3,7
输出应该为 [[1,2,4]]
但实际输出为 [[9,9,9]]

这个代码是从c++改过来的,逻辑一摸一样,怎么会呢?

后来通过debug大法找到了答案
到第一次扫描到正确答案后执行了
res = append(res, path)

image
看似一切正常,但是进行到下一次递归的时候,path的内容改变了,同时res的内容也被改变了
image
这说明append函数直接将path浅拷贝到res中去了
两者现在共享底层,导致我们在操作path的时候,改变了本应该被固定的res
那么解决方法其实也就明确了,对path做一个深拷贝,然后append
go的深拷贝方法可以通过copy函数

a:=[]int{1,2,4}
//copy的拷贝是以小的长度,所以不能指定0,否则copy没有效果
b:=make([]int,len(a))
copy(b,a)

算法正确实现

func combinationSum3(k int, n int) [][]int {
	res := make([][]int, 0)
	path := make([]int, 0)
	var backtracting func(int, int, int, int)
	backtracting = func(n, k, start, target int) {
		if target < 0 || len(path) > k {
			return
		}
		if target == 0 && len(path) == k {
			//深拷贝
			t:=make([]int,len(path))
			res = append(res, t)
			return
		}
		for i := start; i <= 9; i++ {
			path = append(path, i)
			backtracting(n, k, i+1, target-i)
			path = path[:len(path)-1]
		}
	}
	backtracting(n, k, 1, n)
	return res
}
posted @ 2022-09-10 19:28  北方Cc  阅读(288)  评论(0编辑  收藏  举报