/**
PAC:Permutation and combination 的缩写
递归的方式获取所有排列组合
plans 已有的排列组合,递归用的,外部调用时传入一个空的二维数组即可 [][]int{}
num 有多少个数参与排列组合,如传入3,则参与的数是0,1,2
step 每个组合有多少个数
*/
func getPAC(plans [][]int,num int,step int)[][]int{
newPlans := [][]int{}
if len(plans)>0 {
fmt.Println("还有",step-1,"次:")
for _,v := range plans{
for i:=0;i<num;i++ {
group := append(v,i)
fmt.Println(group)
newPlans = append(newPlans,group)
}
}
if step==1 {
fmt.Println("最终结果:",newPlans)
}
}else{
for i:=0;i<num;i++ {
newPlans = append(newPlans,[]int{i})
}
}
if step>1 {
newPlans = getPAC(newPlans,num,step-1)
}
return newPlans
}
使用方法:getPAC([][]int{},3,4)
我写了一个用递归的方式生成所有排列组合的函数
当step<=3
时是正常的,但是如果step>3
,最终结果会出现:[[0 0 0 2] [0 0 0 2] [0 0 0 2] [0 0 1 2] [0 0 1 2] [0 0 1 2] [0 0 2 2] [0 0 2 2] [0 0 2 2] [0 1 0 2] [0 1 0 2]
这种情况,即每个子数组的最后一项都是2
,正常来说最后一项是 0
、1
、2
这3个轮流出现。
一开始我以为是二维slice的子slice生成的时候出了问题,所以我在把子slice加入二维slice前打印了一下,发现是没问题的,但是把slice加入二维slice之后就变了个样
请问这是为什么?因为刚接触go,对go的一些特性还不了解
题外话,如果要实现与上面这个相同且性能更高的方法还是有的
比如逻辑不变把 [][]int 换成 []string
比如把step看成进制,如果是2则2进制、3则3进制,获取这个进制指定位数的最大值+1,然后遍历这个值的次数,把所有的值都加进数组里,也是一个方法,就是抽象了点
但此题目我想了解golang的二维slice到底有什么问题,因为这个问题感觉太奇怪了。
知道原因了,是go的slice的问题,参考个问题:
https://www.zhihu.com/questio...
根据上面的问答,得出一个理解和一个结论
理解:
slice或者数组,其子项的内存地址必定是连续的。slice的长度和容量是两个概念,长度是slice中有多少个值,容量是slice中最多能存多少个值。当slice要增加子项时,总长度不能超过容量。
结论:
append会判断原slice容量够不够,不够则创建一个容量为原来的两倍的新slice,并给新slice添加元素,如果够则直接改变原slice未使用的第一个内存地址的值为新元素。
由结论猜想出的一种bug:
有一个slice:a,容量为4,长度为3。把a用作append的第一个参数,返回值赋予给一些新slice,则这些新slice每个子项的内存地址都是一一相等的,意味着改变了任何一个slice的任意一个值,其它slice对应的值也会跟着变
show you the code