为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
小唯快跑啊 2022-09-26 15:43:47
当我试图从LC解决一个问题“子集II”时,我遇到了一个奇怪的问题。该代码从给定的功率集生成一个功率集。但是,当我运行代码时,它失败了,因为其中一个集合不正确。集合 [0,3,5,7] 被替换为 [0,3,5,9](因此被追加两次)。在将集合附加到 res 之前,我有一个 print 语句(在代码中突出显示),它打印正确的功率集。我能想到的唯一问题是使用指针将值附加到切片中,但是由于它不会同时运行,我不明白为什么会出现争用条件。如果有人能指出我的错误,请表示赞赏。package mainimport (    "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
查看完整描述

2 回答

?
猛跑小猪

TA贡献1858条经验 获得超8个赞

该错误发生在第 40 行:


a = append(t, x[z])

快速修复方法是更改此循环:for


        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)

        }

对此:


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

            var a, b []int

            a = make([]int, len(t))

            copy(a, t)

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

                a = append(a, 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)

        }

这与Go如何使用切片作为数据结构有关。当内置函数的第一个参数是切片参数时,它会复制一些对程序员来说不直观的切片内部数据。然后,它修改了参数切片 和新创建的切片 。appendta


如果您有兴趣了解更多信息,我建议您阅读切片内部。


完整程序已编辑:


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

            a = make([]int, len(t))

            copy(a, t)

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

                a = append(a, 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))

}

新输出:


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]]



查看完整回答
反对 回复 2022-09-26
?
aluckdog

TA贡献1847条经验 获得超7个赞

使用(和重用)切片结果时要非常小心 - 特别是在以后更改这些切片值时。由于切片具有后备数组,因此引用的数据可能会以非常意外的方式更改!


问题的快速解决方法是将切片结果复制到新切片。这可确保对原始切片的更改不会引入 bug(尤其是在递归算法中)。


复制切片:


func copyIntSlice(a []int) []int {

    c := make([]int, len(a))

    copy(c, a) // `a` can now grow/shrink/change without affecting `c`

    return c

}

然后只需从您的主代码中调用它:


aCopy := copyIntSlice(a)

*res = append(*res, aCopy)


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

https://play.golang.org/p/1p8Z4sV9foQ


查看完整回答
反对 回复 2022-09-26
  • 2 回答
  • 0 关注
  • 193 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号