排列組合問題: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個數中取m個(Golang實現)
(一)組合問題 組合是一個基本的數學問題,本程式的目標是輸出從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 描寫敘述: 實現刪除字符串中出現次數最少的字符。若多個字符出現次數一樣,則都刪除。輸出刪除這些單詞後的字符串。 字符串中其他字符保持原來的順序。 輸入: 字符串僅僅包括小