Generate all permutations in go

huangapple go评论101阅读模式
英文:

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 &lt; 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 &quot;fmt&quot;

func nextPerm(p []int) {
	for i := len(p) - 1; i &gt;= 0; i-- {
		if i == 0 || p[i] &lt; 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] &lt; 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&lt;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 &lt; 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), &amp;result)

// result -&gt; [[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 &quot;fmt&quot;

func AllPermutation(a []int) {
	var res [][]int
	calPermutation(a, &amp;res, 0)
	fmt.Println(res)
}
func calPermutation(arr []int, res *[][]int, k int) {
	for i := k; i &lt; 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 &lt; 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 &quot;fmt&quot;

func permute(arr[] int, start int, end int) {
        if start == end {
                fmt.Println(arr)
                return
        }
        for i:=start;i&lt;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{&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;D&quot;}, 2)
toSlice, _ := permutations.Slice()

fmt.Println(&quot;Total:&quot;, 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]
]

huangapple
  • 本文由 发表于 2015年5月14日 06:44:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/30226438.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定