1. 程式人生 > >排列組合問題:n個數中取m個(Golang實現)

排列組合問題:n個數中取m個(Golang實現)

(一)組合問題
組合是一個基本的數學問題,本程式的目標是輸出從n個元素中取m個的所有組合。
例如從[1,2,3]中取出2個數,一共有3中組合:[1,2],[1,3],[2,3]。(組合不考慮順序,即[1,2]和[2,1]屬同一個組合)

本程式的思路(來自網上其他大神):
(1)建立有n個元素陣列,陣列元素的值為1表示選中,為0則沒選中。
(2)初始化,將陣列前m個元素置1,表示第一個組合為前m個數。
(3)從左到右掃描陣列元素值的“10”組合,找到第一個“10”組合後將其變為“01”組合,同時將其左邊的所有“1”全部移動到陣列的最左端。
(4)當某次迴圈沒有找到“10“組合時,說明得到了最後一個組合,迴圈結束。
例如求5中選3的組合:
1 1 1 0 0 //1,2,3
1 1 0 1 0 //1,2,4
1 0 1 1 0 //1,3,4
0 1 1 1 0 //2,3,4
1 1 0 0 1 //1,2,5
1 0 1 0 1 //1,3,5
0 1 1 0 1 //2,3,5
1 0 0 1 1 //1,4,5
0 1 0 1 1 //2,4,5
0 0 1 1 1 //3,4,5

效率情況:20個元素中取5個,共15504個結果,耗時約10ms.
程式碼實現:

package huawei

import (
    "fmt"
    "time"
)

/*
【排列組合問題:n個數中取m個】
*/
func Test10Base() {
    nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    m := 5

    timeStart := time.Now()
    n := len(nums)
    indexs := zuheResult(n, m)
    result := findNumsByIndexs(nums, indexs)
    timeEnd := time.Now()

    fmt.Println("count:"
, len(result)) fmt.Println("result:", result) fmt.Println("time consume:", timeEnd.Sub(timeStart)) //結果是否正確 rightCount := mathZuhe(n, m) if rightCount == len(result) { fmt.Println("結果正確") } else { fmt.Println("結果錯誤,正確結果是:", rightCount) } } //組合演算法(從nums中取出m個數)
func zuheResult(n int, m int) [][]int { if m < 1 || m > n { fmt.Println("Illegal argument. Param m must between 1 and len(nums).") return [][]int{} } //儲存最終結果的陣列,總數直接通過數學公式計算 result := make([][]int, 0, mathZuhe(n, m)) //儲存每一個組合的索引的陣列,1表示選中,0表示未選中 indexs := make([]int, n) for i := 0; i < n; i++ { if i < m { indexs[i] = 1 } else { indexs[i] = 0 } } //第一個結果 result = addTo(result, indexs) for { find := false //每次迴圈將第一次出現的 1 0 改為 0 1,同時將左側的1移動到最左側 for i := 0; i < n-1; i++ { if indexs[i] == 1 && indexs[i+1] == 0 { find = true indexs[i], indexs[i+1] = 0, 1 if i > 1 { moveOneToLeft(indexs[:i]) } result = addTo(result, indexs) break } } //本次迴圈沒有找到 1 0 ,說明已經取到了最後一種情況 if !find { break } } return result } //將ele複製後新增到arr中,返回新的陣列 func addTo(arr [][]int, ele []int) [][]int { newEle := make([]int, len(ele)) copy(newEle, ele) arr = append(arr, newEle) return arr } func moveOneToLeft(leftNums []int) { //計算有幾個1 sum := 0 for i := 0; i < len(leftNums); i++ { if leftNums[i] == 1 { sum++ } } //將前sum個改為1,之後的改為0 for i := 0; i < len(leftNums); i++ { if i < sum { leftNums[i] = 1 } else { leftNums[i] = 0 } } } //根據索引號陣列得到元素陣列 func findNumsByIndexs(nums []int, indexs [][]int) [][]int { if len(indexs) == 0 { return [][]int{} } result := make([][]int, len(indexs)) for i, v := range indexs { line := make([]int, 0) for j, v2 := range v { if v2 == 1 { line = append(line, nums[j]) } } result[i] = line } return result }

注:n個元素中取m個一共有多少種取法可直接通過數學公式計算得出,即:

//數學方法計算排列數(從n中取m個數)
func mathPailie(n int, m int) int {
    return jieCheng(n) / jieCheng(n-m)
}

//數學方法計算組合數(從n中取m個數)
func mathZuhe(n int, m int) int {
    return jieCheng(n) / (jieCheng(n-m) * jieCheng(m))
}

//階乘
func jieCheng(n int) int {
    result := 1
    for i := 2; i <= n; i++ {
        result *= i
    }

    return result
}

通過此公式可以簡單的驗證一下上述程式的結果是否正確。

(二)排列問題
從n個數中取出m個進行排列,其實就是組合演算法之後,對選中的m個數進行全排列。而全排列的問題在之前的文章中已經討論過了。
程式碼實現:

func pailieResult(nums []int, m int) [][]int {
    //組合結果
    zuhe := zuheResult(nums, m)

    //儲存最終排列結果
    result := make([][]int, 0)
    //遍歷組合結果,對每一項進行全排列
    for _, v := range zuhe {
        p := quanPailie(v)
        result = append(result, p...)
    }

    return result
}

//n個數全排列
//如輸入[1 2 3],則返回[123 132 213 231 312 321]
func quanPailie(nums []int) [][]int {
    COUNT := len(nums)
    //檢查
    if COUNT == 0 || COUNT > 10 {
        panic("Illegal argument. nums size must between 1 and 9.")
    }

    //如果只有一個數,則直接返回
    if COUNT == 1 {
        return [][]int{nums}
    }

    //否則,將最後一個數插入到前面的排列數中的所有位置
    return insertItem(quanPailie(nums[:COUNT-1]), nums[COUNT-1])
}

func insertItem(res [][]int, insertNum int) [][]int {
    //儲存結果的slice
    result := make([][]int, len(res)*(len(res[0])+1))

    index := 0
    for _, v := range res {
        for i := 0; i < len(v); i++ {
            //在v的每一個元素前面插入新元素
            result[index] = insertToSlice(v, i, insertNum)
            index++
        }

        //在v最後面插入新元素
        result[index] = append(v, insertNum)
        index++
    }

    return result
}

//將元素value插入到陣列nums中索引為index的位置
func insertToSlice(nums []int, index int, value int) []int {
    result := make([]int, len(nums)+1)
    copy(result[:index], nums[:index])
    result[index] = value
    copy(result[index+1:], nums[index:])

    return result
}

相關推薦

排列組合問題n個數mGolang實現

(一)組合問題 組合是一個基本的數學問題,本程式的目標是輸出從n個元素中取m個的所有組合。 例如從[1,2,3]中取出2個數,一共有3中組合:[1,2],[1,3],[2,3]。(組合不考慮順序,即[1,2]和[2,1]屬同一個組合) 本程式的思路(來自網

排列組合問題n個數k個數

() spa 條件 esp sizeof pac ret emp space /************************************有0~n-1共n個數,從其中任取k個數,*已知這k個數的和能被n整除,求這樣的*k個數的組合的個數sum,*輸入:n,k*

輸出N個數M個數的所有組合排列情況

一般思路是由組合算排列,現在藉助Next_permutation函式由排列到組合。 1.組合 讀入一個字串,一個整數n,輸出字串中取n個字元的所有組合情況 演算法:藉助Next_permutation函式,構造一個大小為len=str.length()的陣列,0表示要輸出

hdu 3915 Game 求N個數若干數字使得它們的異或值為0的方法數 高斯消元(mod2)

Problem Description   Mr.Frost is a child who is too simple, sometimes naive, always plays some simple but interesting games with his fri

C++排列組合N個數選擇M個數的所有情況

 待選擇的數存放在in矩陣中,矩陣的大小為N,從中選出target=M個數,給出所有可能情況。 思路: in矩陣存放的數為(M=2,N=4): 下標 0 1 2 3 元素 1 2 3 4  定義一個

OC組合演算法 從N個數裡面M個數組合

- (void)newCaculateSort{ [self combination:9 in:4]; } - (void)combination:(int)n in:(int)m{ if (m == 0) { [_resultArray addObject:[NSArray

階乘與排列的例子n元素m元素組成互不相同並且不重複的三位數

public static void main(String[] args) { //1.編寫一個程式,輸入n,求n!(用遞迴的方式實現)。4*3*2*1=4! 注:0!=1 System.out.println("4的階乘為:" + getFactoria

n個數選取m個數的所有組合

非遞迴實現: #define N 7 #define M 3 int main() { int array[N] = { 1,2,3,4,5,6 ,7 }; int i, j, k; for (i = 0; i<=N-M; i++) for (j = i +

組合從長度為n的字串m字元---java兩種實現方法

對於這類組合問題,雖然感覺很簡單,但是用java程式碼實現起來卻不是那麼容易的。 這其中最容易用到的應該是遞迴的思想了,這種方法也比較容易理解: 方法一: 遞迴實現程式碼: /** * 可能種類在4000萬的時候時間效率為7.6s左右

程式設計題n個數選取m個數,計算m個數的和s,判斷剩餘n-m個數是否存在等於s的數,如果存在,輸出最大值

描述:從n個數中選取m個數,計算m個數的和s,判斷剩餘n-m個數中是否存在等於s的數,如果存在,輸出最大值。第一行輸入n和m值,第二行輸入n個數,輸出最大值。例如:輸入:6 2          1 2 5 3 7 4輸出:7分析:1+2=3;2+5=7;2+3=5;3+4=

遞迴實現n個數選取m個數的所有組合

有n(n>0)個數,從中選取m(n>m>0)個數,找出所有的組合情況(不分順序)。這樣的組合共有 Cmn=n×(n−1)×⋯×(n−m+1)m!. 一個數組 data 有 n 個元

n位數m位的組合

public void printArr(String[] arr, int from, int to) { System.out.print("("); for(int

牛客網在線編程n個數出現次數大於等於n/2的數

判斷 包含 ring 描述 [] ati ava 出現的次數 題目 題目描述: 輸入n個整數,輸出出現次數大於等於數組長度一半的數。輸入描述:每個測試輸入包含 n個空格分割的n個整數,n不超過100,其中有一個整數出現次數大於等於n/2。輸出描述:輸出出現次數大於等於n/2

n個數選擇m個數來 Java實現(順序不固定)

public static List<int[]> collect = new ArrayList<int[]>(); public static void permutation(int[] a, int begin0, int begin,

POJ 2249 Binomial Showdown我的水題之路——求n個數m個數的值

Binomial Showdown Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15158 Accepted: 4629 Description In how many ways can

n個數最大值與最小值

#include<stdio.h> int main() {    int max,min,i,a,n;    scanf("%d",&a);    max=min=a;    for(i=1;i<n;i++)    {     scanf("%d

列印從n個數選取m個數的組合數

   列印從n個數種選取m個數的組合數 方法一:利用遞迴思想。 //從後往前選取,選定位置i後,再在前i-1個裡面選取m-1個。 //如 1 2 3 4 5 中選取 3 個 //1、選取5後,再在前4個裡面選取2個,而前4個裡面選取2個又是一個子問題,遞迴即可。 //2、如

【演算法與資料結構】在n個數第k大的數基礎篇

題目介紹 在n個數中取第k大的數(基礎篇),之所以叫基礎篇是因為還有很多更高階的演算法,這些以後再討論。本文用兩種最基本的方法來解決這個問題。使用java語言描述。例子是十個數中取第三大的。 演算法

演算法基礎排列組合問題-全排列Golang實現

【排列組合問題】 一共N輛火車(0<N<10),每輛火車以數字1-9編號,要求以字典序排序輸出火車出站的序列號。 輸入: 包括N個正整數(0<N<10),範圍為1到9,數字之間用空格分割,字串首位不包含空格。 輸出: 輸出以字典

算法基礎刪除字符串出現次數最少的字符Golang實現

cfb 出現次數 英文字母 clas har str 長度 == tracking 描寫敘述: 實現刪除字符串中出現次數最少的字符。若多個字符出現次數一樣,則都刪除。輸出刪除這些單詞後的字符串。 字符串中其他字符保持原來的順序。 輸入: 字符串僅僅包括小