使用指针追加到片 [][]int 时出错

当我试图从LC解决一个问题“子集II”时,我遇到了一个奇怪的问题。该代码从给定的功率集生成一个功率集。但是,当我运行代码时,它失败了,因为其中一个集合不正确。


集合 [0,3,5,7] 被替换为 [0,3,5,9](因此被追加两次)。


在将集合附加到 res 之前,我有一个 print 语句(在代码中突出显示),它打印正确的功率集。


我能想到的唯一问题是使用指针将值附加到切片中,但是由于它不会同时运行,我不明白为什么会出现争用条件。如果有人能指出我的错误,请表示赞赏。


package main


import (

    "fmt"

    "sort"

)


func ValueCount( nums []int) map[int]int{

  hm := make(map[int]int)

  for _,v := range(nums){

    if c, ok := hm[v]; ok {

      hm[v] = c + 1

    }else{

      hm[v] = 1

    }

  }

  return hm

}


func subsetsWithDup(nums []int) [][]int {

    var res [][]int

    res = append(res,[]int{})

    sort.Ints(nums)

  hashMap := ValueCount(nums)

  var t []int

  printTest(nums, t, &res, hashMap)

    return res

}



func printTest(nums []int, t []int, res *[][]int, hm map[int]int) {

  if len(nums) == 0 {

    return

  }

  for i:= 0; i < len(nums); {

    v := nums[i]

    x := nums[i:]

    for  k:= 0; k< hm[v]; k++ {

      var a,b []int

      for z:= 0; z<k+1; z++ { 

        a = append(t,x[z])

      }

      fmt.Println(a) // <--------- Prints the values that gets appended to res

      *res = append(*res, a)    

      b = a

      printTest(nums[i+hm[v]:], b, res, hm)

    }

    i += hm[v]

  }

  

}


func main(){

    n := []int{9,0,3,5,7}

    fmt.Println("Find the power set of:", n)

    fmt.Println(subsetsWithDup(n))

}


// [0,3,5,7] changes to 

// [0,3,5,9] in the output


小唯快跑啊
浏览 194回答 2
2回答

猛跑小猪

该错误发生在第 40 行:a = append(t, x[z])快速修复方法是更改此循环:for&nbsp; &nbsp; &nbsp; &nbsp; for k := 0; k < hm[v]; k++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var a, b []int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for z := 0; z < k+1; z++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a = append(t, x[z])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(a) // <--------- Prints the values that gets appended to res&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *res = append(*res, a)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; printTest(nums[i+hm[v]:], b, res, hm)&nbsp; &nbsp; &nbsp; &nbsp; }对此:&nbsp; &nbsp; &nbsp; &nbsp; for k := 0; k < hm[v]; k++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var a, b []int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a = make([]int, len(t))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; copy(a, t)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for z := 0; z < k+1; z++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a = append(a, x[z])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(a) // <--------- Prints the values that gets appended to res&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *res = append(*res, a)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; printTest(nums[i+hm[v]:], b, res, hm)&nbsp; &nbsp; &nbsp; &nbsp; }这与Go如何使用切片作为数据结构有关。当内置函数的第一个参数是切片参数时,它会复制一些对程序员来说不直观的切片内部数据。然后,它修改了参数切片 和新创建的切片 。appendta如果您有兴趣了解更多信息,我建议您阅读切片内部。完整程序已编辑:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "sort")func ValueCount(nums []int) map[int]int {&nbsp; &nbsp; hm := make(map[int]int)&nbsp; &nbsp; for _, v := range nums {&nbsp; &nbsp; &nbsp; &nbsp; if c, ok := hm[v]; ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hm[v] = c + 1&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hm[v] = 1&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return hm}func subsetsWithDup(nums []int) [][]int {&nbsp; &nbsp; var res [][]int&nbsp; &nbsp; res = append(res, []int{})&nbsp; &nbsp; sort.Ints(nums)&nbsp; &nbsp; hashMap := ValueCount(nums)&nbsp; &nbsp; var t []int&nbsp; &nbsp; printTest(nums, t, &res, hashMap)&nbsp; &nbsp; return res}func printTest(nums []int, t []int, res *[][]int, hm map[int]int) {&nbsp; &nbsp; if len(nums) == 0 {&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; for i := 0; i < len(nums); {&nbsp; &nbsp; &nbsp; &nbsp; v := nums[i]&nbsp; &nbsp; &nbsp; &nbsp; x := nums[i:]&nbsp; &nbsp; &nbsp; &nbsp; for k := 0; k < hm[v]; k++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var a, b []int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a = make([]int, len(t))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; copy(a, t)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for z := 0; z < k+1; z++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a = append(a, x[z])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(a) // <--------- Prints the values that gets appended to res&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *res = append(*res, a)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; printTest(nums[i+hm[v]:], b, res, hm)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; i += hm[v]&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; n := []int{9, 0, 3, 5, 7}&nbsp; &nbsp; fmt.Println("Find the power set of:", n)&nbsp; &nbsp; fmt.Println(subsetsWithDup(n))}新输出:Find the power set of: [9 0 3 5 7][0][0 3][0 3 5][0 3 5 7][0 3 5 7 9][0 3 5 9][0 3 7][0 3 7 9][0 3 9][0 5][0 5 7][0 5 7 9][0 5 9][0 7][0 7 9][0 9][3][3 5][3 5 7][3 5 7 9][3 5 9][3 7][3 7 9][3 9][5][5 7][5 7 9][5 9][7][7 9][9][[] [0] [0 3] [0 3 5] [0 3 5 7] [0 3 5 7 9] [0 3 5 9] [0 3 7] [0 3 7 9] [0 3 9] [0 5] [0 5 7] [0 5 7 9] [0 5 9] [0 7] [0 7 9] [0 9] [3] [3 5] [3 5 7] [3 5 7 9] [3 5 9] [3 7] [3 7 9] [3 9] [5] [5 7] [5 7 9] [5 9] [7] [7 9] [9]]

aluckdog

使用(和重用)切片结果时要非常小心 - 特别是在以后更改这些切片值时。由于切片具有后备数组,因此引用的数据可能会以非常意外的方式更改!问题的快速解决方法是将切片结果复制到新切片。这可确保对原始切片的更改不会引入 bug(尤其是在递归算法中)。复制切片:func copyIntSlice(a []int) []int {&nbsp; &nbsp; c := make([]int, len(a))&nbsp; &nbsp; copy(c, a) // `a` can now grow/shrink/change without affecting `c`&nbsp; &nbsp; return c}然后只需从您的主代码中调用它:aCopy := copyIntSlice(a)*res = append(*res, aCopy)printTest(nums[i+hm[v]:], aCopy, res, hm)https://play.golang.org/p/1p8Z4sV9foQ
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go