最近我发现了一些我无法理解的代码,下面是我的代码:
func subsetsWithDup(nums []int) [][]int {
if len(nums) == 0 {
return [][]int{[]int{}}
}
sort.Ints(nums)
result := [][]int{}
backtracking(nums, &result, []int{}, 0)
return result
}
func backtracking(nums []int, result *[][]int, tempList []int, start int) {
*result = append(*result, tempList)
for i := start; i < len(nums); i++ {
if i > start && nums[i] == nums[i-1] {
continue
}
tempList = append(tempList, nums[i])
backtracking(nums, result, tempList, i+1)
tempList = tempList[:len(tempList)-1:len(tempList)-1]
}
}
和另一种方法:
func subsetsWithDup(nums []int) [][]int {
sort.Ints(nums)
return subsets(nums, []int{}, [][]int{})
}
func subsets(nums []int, result []int, results [][]int) [][]int {
newR := make([]int, len(result))
copy(newR, result)
results = append(results, newR)
if len(nums) == 0 {return results}
for i := 0; i < len(nums); i++ {
if i > 0 && nums[i] == nums[i - 1] {continue}
result = append(result, nums[i])
results = subsets(nums[i + 1:], result, results)
result = result[:len(result) - 1]
}
return results
}
在第一种方法中,我使用以下代码:
tempList = tempList[:len(tempList)-1:len(tempList)-1]
它有效,但如果我将其更改为:
tempList = tempList[:len(tempList)-1]
它不起作用。在第二种使用复制功能的方法也有效。我想知道代码背后会发生什么,感谢任何帮助,谢谢。
答案 0 :(得分:1)
在Go中,slice是一种指针类型,用于维护有关底层数组的信息,因此更改底层数组会导致切片值发生变化,这有时可能会令人惊讶。
谜题的第二部分是append
如果cap
的{{1}}足够,则会修改基础数组。文件:
追加内置函数将元素附加到切片的末尾。 如果它具有足够的容量,则目标将被复制到 适应新元素。如果没有,则为新的底层数组 将被分配。 Append返回更新的切片。因此 必须存储追加的结果,通常在变量持有中 切片本身。
因此,在尝试失败时,slice
可能会更改tempList = append(tempList, nums[i])
中先前存储的切片的值。
另一方面,第二种方法创建一个带有新底层数组的新切片并明确地复制到它,因此避免了错误。第一种方法更精细,因为它使用完整切片表达式:result
。代码限制了新切片的tempList[:len(tempList)-1:len(tempList)-1]
,因此cap
每次都必须分配一个新的底层数组,而不是使用orignal数组。
有关完整切片表达式(规范)的更多信息:
对于数组,指向数组的指针,或切片a(但不是字符串),主表达式
append
构造一个相同类型的切片,并且具有与简单切片表达式相同的长度和元素a [low:high]。此外,它通过将切片的容量设置为max - low来控制切片的容量。只能省略第一个索引;它默认为0.切片后的数组
a[low : high : max]
切片t的类型为[] int,长度为2,容量为4,元素为
a := [5]int{1, 2, 3, 4, 5}
t := a[1:3:5]