生成特定长度的组合/排列

时间:2017-12-12 17:38:10

标签: algorithm go combinations

项目更复杂,但阻塞问题是:如何从列表中生成特定长度的单词序列?

我已经找到了如何生成所有可能的组合(见下文),但问题是我只需要特定长度的组合。

Wolfram工作示例(虽然它使用了排列,我只需要组合(顺序并不重要)):

Permutations[{a, b, c, d}, {3}]

示例(伪去):

  list := []string{"alice", "moon", "walks", "mars", "sings", "guitar", "bravo"}
  var premutationOf3
  premutationOf3 = premuate(list, 3)
  // this should return a list of all premutations such 
  // [][]string{[]string{"alice", "walks", "moon"}, []string{"alice", "signs", "guitar"} ....}

当前代码预先设定所有可能的序列(无长度限制)

    for _, perm := range permutations(list) {
        fmt.Printf("%q\n", perm)
    }

func permutations(arr []string) [][]string {
    var helper func([]string, int)
    res := [][]string{}

    helper = func(arr []string, n int) {
        if n == 1 {
            tmp := make([]string, 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
}

1 个答案:

答案 0 :(得分:1)

我实现了在Go中生成组合的旋转算法。这是我的实施:

package twiddle

// Twiddle type contains all information twiddle algorithm
// need between each iteration.
type Twiddle struct {
    p   []int
    b   []bool
    end bool
}

// New creates new twiddle algorithm instance
func New(m int, n int) *Twiddle {
    p := make([]int, n+2)
    b := make([]bool, n)

    // initiate p
    p[0] = n + 1

    var i int

    for i = 1; i != n-m+1; i++ {
        p[i] = 0
    }
    for i != n+1 {
        p[i] = i + m - n
        i++
    }

    p[n+1] = -2

    if m == 0 {
        p[1] = 1
    }

    // initiate b
    for i = 0; i != n-m; i++ {
        b[i] = false
    }
    for i != n {
        b[i] = true
        i++
    }

    return &Twiddle{
        p: p,
        b: b,
    }
}

// Next creates next combination and return it.
// it returns nil on end of combinations
func (t *Twiddle) Next() []bool {
    if t.end {
        return nil
    }

    r := make([]bool, len(t.b))
    for i := 0; i < len(t.b); i++ {
        r[i] = t.b[i]
    }

    x, y, end := t.twiddle()
    t.b[x] = true
    t.b[y] = false
    t.end = end

    return r
}

func (t *Twiddle) twiddle() (int, int, bool) {
    var i, j, k int
    var x, y int

    j = 1
    for t.p[j] <= 0 {
        j++
    }

    if t.p[j-1] == 0 {
        for i = j - 1; i != 1; i-- {
            t.p[i] = -1
        }
        t.p[j] = 0
        x = 0
        t.p[1] = 1
        y = j - 1
    } else {
        if j > 1 {
            t.p[j-1] = 0
        }
        j++
        for t.p[j] > 0 {
            j++
        }
        k = j - 1
        i = j
        for t.p[i] == 0 {
            t.p[i] = -1
            i++
        }
        if t.p[i] == -1 {
            t.p[i] = t.p[k]
            x = i - 1
            y = k - 1
            t.p[k] = -1
        } else {
            if i == t.p[0] {
                return x, y, true
            }

            t.p[j] = t.p[i]
            t.p[i] = 0
            x = j - 1
            y = i - 1
        }
    }
    return x, y, false

}

你可以按照以下方式使用我的tweedle包:

tw := tweedle.New(1, 2)

for b := tw.Next(); b != nil; b = tw.Next() {
    fmt.Println(b)
}