英文:
Generate all permutations in go
问题
我正在寻找一种生成列表元素的所有可能排列的方法。类似于Python中的itertools.permutations(arr)
。
permutations ([])
[]
permutations ([1])
[1]
permutations ([1,2])
[1, 2]
[2, 1]
permutations ([1,2,3])
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
与此不同的是,我不关心排列是否按需生成(类似于Python中的生成器)或一次性生成。我也不关心它们是否按字典顺序排序。我只需要以某种方式获取这些n!
个排列。
英文:
I am looking for a way to generate all possible permutations of a list of elements. Something similar to python's itertools.permutations(arr)
permutations ([])
[]
permutations ([1])
[1]
permutations ([1,2])
[1, 2]
[2, 1]
permutations ([1,2,3])
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
With the difference that I do not care whether permutations would be generated on demand (like a generator in python) or all together. I also do not care whether they will be lexicographically sorted. All I need is to somehow get these n!
permutations.
答案1
得分: 31
有很多算法可以生成排列。我找到的其中一个最简单的是Heap's算法:
它通过选择一对要交换的元素,从前一个排列生成每个排列。
上面的链接中概述了这个想法和一个按顺序打印排列的伪代码。这是我实现的返回所有排列的算法:
func permutations(arr []int) [][]int {
var helper func([]int, int)
res := [][]int{}
helper = func(arr []int, n int) {
if n == 1 {
tmp := make([]int, len(arr))
copy(tmp, arr)
res = append(res, tmp)
} else {
for i := 0; i < n; i++ {
helper(arr, n-1)
if n%2 == 1 {
tmp := arr[i]
arr[i] = arr[n-1]
arr[n-1] = tmp
} else {
tmp := arr[0]
arr[0] = arr[n-1]
arr[n-1] = tmp
}
}
}
}
helper(arr, len(arr))
return res
}
这是如何使用它的示例(Go playground):
arr := []int{1, 2, 3}
fmt.Println(permutations(arr))
[[1 2 3] [2 1 3] [3 2 1] [2 3 1] [3 1 2] [1 3 2]]
需要注意的一点是,这些排列不是按字典顺序排序的(就像你在itertools.permutations
中看到的那样)。如果出于某种原因你需要按顺序排序,我找到的一种方法是使用阶乘数系统生成它们(在"permutation section"中有描述),它可以快速找到第n个字典顺序的排列。
另外,你也可以在这里和这里查看其他人的代码。
英文:
There are a lot of the algorithms that generate permutations. One of the easiest I found is Heap's algorithm:
> It generates each permutation from the previous one by choosing a pair
> of elements to interchange.
The idea and a pseudocode that prints the permutations one after another is outlined in the above link. Here is my implementation of the algorithm which returns all permutations
func permutations(arr []int)[][]int{
var helper func([]int, int)
res := [][]int{}
helper = func(arr []int, n int){
if n == 1{
tmp := make([]int, len(arr))
copy(tmp, arr)
res = append(res, tmp)
} else {
for i := 0; i < n; i++{
helper(arr, n - 1)
if n % 2 == 1{
tmp := arr[i]
arr[i] = arr[n - 1]
arr[n - 1] = tmp
} else {
tmp := arr[0]
arr[0] = arr[n - 1]
arr[n - 1] = tmp
}
}
}
}
helper(arr, len(arr))
return res
}
and here is an example of how to use it (Go playground):
arr := []int{1, 2, 3}
fmt.Println(permutations(arr))
[[1 2 3] [2 1 3] [3 2 1] [2 3 1] [3 1 2] [1 3 2]]
One thing to notice that the permutations are not sorted lexicographically (as you have seen in itertools.permutations
). If for some reason you need it to be sorted, one way I have found it is to generate them from a factorial number system (it is described in permutation section
and allows to quickly find n-th lexicographical permutation).
P.S. you can also take a look at others people code here and here
答案2
得分: 16
以下是迭代遍历所有排列而不先生成它们的代码。切片 p
以 Fisher-Yates 洗牌算法中的偏移量形式保留中间状态。这个算法的一个好处是,p
的零值描述了恒等排列。
package main
import "fmt"
func nextPerm(p []int) {
for i := len(p) - 1; i >= 0; i-- {
if i == 0 || p[i] < len(p)-i-1 {
p[i]++
return
}
p[i] = 0
}
}
func getPerm(orig, p []int) []int {
result := append([]int{}, orig...)
for i, v := range p {
result[i], result[i+v] = result[i+v], result[i]
}
return result
}
func main() {
orig := []int{11, 22, 33}
for p := make([]int, len(orig)); p[0] < len(p); nextPerm(p) {
fmt.Println(getPerm(orig, p))
}
}
希望对你有帮助!
英文:
Here's code that iterates over all permutations without generating them all first. The slice p
keeps the intermediate state as offsets in a Fisher-Yates shuffle algorithm. This has the nice property that the zero value for p
describes the identity permutation.
package main
import "fmt"
func nextPerm(p []int) {
for i := len(p) - 1; i >= 0; i-- {
if i == 0 || p[i] < len(p)-i-1 {
p[i]++
return
}
p[i] = 0
}
}
func getPerm(orig, p []int) []int {
result := append([]int{}, orig...)
for i, v := range p {
result[i], result[i+v] = result[i+v], result[i]
}
return result
}
func main() {
orig := []int{11, 22, 33}
for p := make([]int, len(orig)); p[0] < len(p); nextPerm(p) {
fmt.Println(getPerm(orig, p))
}
}
答案3
得分: 2
var res [][]int
func permute(nums []int) [][]int {
res = make([][]int, 0)
n := len(nums)
var backTrack func(int)
backTrack = func(first int) {
if first == n {
temp := make([]int, n)
copy(temp, nums)
res = append(res, temp)
}
for i := first; i < n; i++ {
nums[first], nums[i] = nums[i], nums[first]
backTrack(first + 1)
nums[first], nums[i] = nums[i], nums[first]
}
}
backTrack(0)
return res
}
var res [][]int
func permute(nums []int) [][]int {
res = make([][]int, 0)
n := len(nums)
var backTrack func(int)
backTrack = func(first int) {
if first == n {
temp := make([]int, n)
copy(temp, nums)
res = append(res, temp)
}
for i := first; i < n; i++ {
nums[first], nums[i] = nums[i], nums[first]
backTrack(first + 1)
nums[first], nums[i] = nums[i], nums[first]
}
}
backTrack(0)
return res
}
英文:
var res [][]int
func permute(nums []int) [][]int {
res=make([][]int,0)
n:=len(nums)
var backTrack func(int)
backTrack=func(first int){
if first == n{
temp:=make([]int, n)
copy(temp,nums)
res = append(res, temp)
}
for i:=first;i<n;i++{
nums[first],nums[i] = nums[i],nums[first]
backTrack(first+1)
nums[first],nums[i] = nums[i],nums[first]
}
}
backTrack(0)
return res
}
答案4
得分: 0
在我的例子中,我有一个对数组的引用,然后对你的示例进行了一些更改:
func generateIntPermutations(array []int, n int, result *[][]int) {
if n == 1 {
dst := make([]int, len(array))
copy(dst, array[:])
*result = append(*result, dst)
} else {
for i := 0; i < n; i++ {
generateIntPermutations(array, n-1, result)
if n%2 == 0 {
// Golang 允许我们进行多重赋值
array[0], array[n-1] = array[n-1], array[0]
} else {
array[i], array[n-1] = array[n-1], array[i]
}
}
}
}
numbers := []int{0, 1, 2}
var result [][]int
generateIntPermutations(numbers, len(numbers), &result)
// result -> [[0 1 2] [1 0 2] [2 1 0] [1 2 0] [2 0 1] [0 2 1]]
结果 -> [[0 1 2] [1 0 2] [2 1 0] [1 2 0] [2 0 1] [0 2 1]]
英文:
In my case I had a reference to an array, then I've did a few changes in your example:
func generateIntPermutations(array []int, n int, result *[][]int) {
if n == 1 {
dst := make([]int, len(array))
copy(dst, array[:])
*result = append(*result, dst)
} else {
for i := 0; i < n; i++ {
generateIntPermutations(array, n-1, result)
if n%2 == 0 {
// Golang allow us to do multiple assignments
array[0], array[n-1] = array[n-1], array[0]
} else {
array[i], array[n-1] = array[n-1], array[i]
}
}
}
}
numbers := []int{0, 1, 2}
var result [][]int
generateIntPermutations(numbers, len(numbers), &result)
// result -> [[0 1 2] [1 0 2] [2 1 0] [1 2 0] [2 0 1] [0 2 1]]
答案5
得分: 0
另一个工作代码
package permutations
import "fmt"
func AllPermutation(a []int) {
var res [][]int
calPermutation(a, &res, 0)
fmt.Println(res)
}
func calPermutation(arr []int, res *[][]int, k int) {
for i := k; i < len(arr); i++ {
swap(arr, i, k)
calPermutation(arr, res, k+1)
swap(arr, k, i)
}
if k == len(arr)-1 {
r := make([]int, len(arr))
copy(r, arr)
*res = append(*res, r)
return
}
}
func swap(arr []int, i, k int) {
arr[i], arr[k] = arr[k], arr[i]
}
//结果 [[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 2 1] [3 1 2]]
请注意,这是一个用于生成给定整数数组的所有排列的代码。在AllPermutation
函数中,我们创建了一个二维整数切片res
来存储所有的排列结果。然后,我们调用calPermutation
函数来计算排列,并将结果存储在res
中。calPermutation
函数使用递归的方式生成排列,通过交换数组中的元素来实现。最后,我们将结果打印出来。
希望对你有帮助!如果你有任何其他问题,请随时问我。
英文:
Another Working code
package permutations
import "fmt"
func AllPermutation(a []int) {
var res [][]int
calPermutation(a, &res, 0)
fmt.Println(res)
}
func calPermutation(arr []int, res *[][]int, k int) {
for i := k; i < len(arr); i++ {
swap(arr, i, k)
calPermutation(arr, res, k+1)
swap(arr, k, i)
}
if k == len(arr)-1 {
r := make([]int, len(arr))
copy(r, arr)
*res = append(*res, r)
return
}
}
func swap(arr []int, i, k int) {
arr[i], arr[k] = arr[k], arr[i]
}
//result [[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 2 1] [3 1 2]]
答案6
得分: 0
这是另一种变体:
// 堆算法
func permutations(arr []int, l int, p [][]int) [][]int {
if l == 1 { p = append(p, append([]int{}, arr...)) }
for i := 0 ; i < l ; i++ {
p = permutations(arr, l-1, p)
if l % 2 == 1 {
arr[0], arr[l-1] = arr[l-1], arr[0]
} else {
arr[i], arr[l-1] = arr[l-1], arr[i]
}
}
return p
}
英文:
Here is another variation:
// heap algorithm
func permutations(arr []int, l int, p [][]int) [][]int {
if l == 1 { p = append(p, append([]int{}, arr...)) }
for i := 0 ; i < l ; i++ {
p = permutations(arr, l-1, p)
if l % 2 == 1 {
arr[0], arr[l-1] = arr[l-1], arr[0]
} else {
arr[i], arr[l-1] = arr[l-1], arr[i]
}
}
return p
}
答案7
得分: 0
使用简单算法在golang中实现的排列代码
package main
import "fmt"
func permute(arr []int, start int, end int) {
if start == end {
fmt.Println(arr)
return
}
for i := start; i < end; i++ {
arr[i], arr[start] = arr[start], arr[i]
permute(arr, start+1, end)
arr[i], arr[start] = arr[start], arr[i]
}
}
func main() {
arr := []int{1, 2, 3}
end := len(arr)
start := 0
permute(arr, start, end)
}
以上是使用简单算法在golang中实现的排列代码。
英文:
Permutation code using simple algorithm in golang
package main
import "fmt"
func permute(arr[] int, start int, end int) {
if start == end {
fmt.Println(arr)
return
}
for i:=start;i<end;i++ {
arr[i],arr[start] = arr[start],arr[i]
permute(arr,start+1,end)
arr[i],arr[start] = arr[start],arr[i]
}
}
func main() {
arr := []int{1,2,3}
end := len(arr)
start := 0
permute(arr,start,end)
}
答案8
得分: 0
你可以使用Iterium包来完成这个任务:https://github.com/mowshon/iterium
以下是你问题的示例代码:
permutations := iterium.Permutations([]string{"A", "B", "C", "D"}, 2)
toSlice, _ := permutations.Slice()
fmt.Println("Total:", permutations.Count())
fmt.Println(toSlice)
结果:
Total: 12
[
[A, B] [A, C] [A, D] [B, A] [B, C] [B, D]
[C, B] [C, A] [C, D] [D, B] [D, C] [D, A]
]
英文:
You can use the Iterium package for this task: https://github.com/mowshon/iterium
Example code for your question:
permutations := iterium.Permutations([]string{"A", "B", "C", "D"}, 2)
toSlice, _ := permutations.Slice()
fmt.Println("Total:", permutations.Count())
fmt.Println(toSlice)
Result:
Total: 12
[
[A, B] [A, C] [A, D] [B, A] [B, C] [B, D]
[C, B] [C, A] [C, D] [D, B] [D, C] [D, A]
]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论