欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言實(shí)現(xiàn)的排列組合問題實(shí)例(n個數(shù)中取m個)

 更新時間:2017年02月20日 12:04:50   作者:books1958  
這篇文章主要介紹了Go語言實(shí)現(xiàn)的排列組合問題,結(jié)合實(shí)例形式分析了Go語言實(shí)現(xiàn)排列組合數(shù)學(xué)運(yùn)算的原理與具體操作技巧,需要的朋友可以參考下

本文實(shí)例講述了Go語言實(shí)現(xiàn)的排列組合問題。分享給大家供大家參考,具體如下:

(一)組合問題

組合是一個基本的數(shù)學(xué)問題,本程序的目標(biāo)是輸出從n個元素中取m個的所有組合。

例如從[1,2,3]中取出2個數(shù),一共有3中組合:[1,2],[1,3],[2,3]。(組合不考慮順序,即[1,2]和[2,1]屬同一個組合)

本程序的思路(來自網(wǎng)上其他大神):

(1)創(chuàng)建有n個元素數(shù)組,數(shù)組元素的值為1表示選中,為0則沒選中。
(2)初始化,將數(shù)組前m個元素置1,表示第一個組合為前m個數(shù)。
(3)從左到右掃描數(shù)組元素值的“10”組合,找到第一個“10”組合后將其變?yōu)椤?1”組合,同時將其左邊的所有“1”全部移動到數(shù)組的最左端。
(4)當(dāng)某次循環(huán)沒有找到“10“組合時,說明得到了最后一個組合,循環(huán)結(jié)束。

例如求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個結(jié)果,耗時約10ms.

代碼實(shí)現(xiàn):

復(fù)制代碼 代碼如下:
package huawei
import (
    "fmt"
    "time"
)
/*
【排列組合問題:n個數(shù)中取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))
    //結(jié)果是否正確
    rightCount := mathZuhe(n, m)
    if rightCount == len(result) {
        fmt.Println("結(jié)果正確")
    } else {
        fmt.Println("結(jié)果錯誤,正確結(jié)果是:", rightCount)
    }
}
//組合算法(從nums中取出m個數(shù))
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{}
    }
    //保存最終結(jié)果的數(shù)組,總數(shù)直接通過數(shù)學(xué)公式計算
    result := make([][]int, 0, mathZuhe(n, m))
    //保存每一個組合的索引的數(shù)組,1表示選中,0表示未選中
    indexs := make([]int, n)
    for i := 0; i < n; i++ {
        if i < m {
            indexs[i] = 1
        } else {
            indexs[i] = 0
        }
    }
    //第一個結(jié)果
    result = addTo(result, indexs)
    for {
        find := false
        //每次循環(huán)將第一次出現(xiàn)的 1 0 改為 0 1,同時將左側(cè)的1移動到最左側(cè)
        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
            }
        }
        //本次循環(huán)沒有找到 1 0 ,說明已經(jīng)取到了最后一種情況
        if !find {
            break
        }
    }
    return result
}
//將ele復(fù)制后添加到arr中,返回新的數(shù)組
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
        }
    }
}
//根據(jù)索引號數(shù)組得到元素數(shù)組
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個一共有多少種取法可直接通過數(shù)學(xué)公式計算得出,即:

復(fù)制代碼 代碼如下:
//數(shù)學(xué)方法計算排列數(shù)(從n中取m個數(shù))
func mathPailie(n int, m int) int {
    return jieCheng(n) / jieCheng(n-m)
}
//數(shù)學(xué)方法計算組合數(shù)(從n中取m個數(shù))
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
}

通過此公式可以簡單的驗(yàn)證一下上述程序的結(jié)果是否正確。

(二)排列問題

從n個數(shù)中取出m個進(jìn)行排列,其實(shí)就是組合算法之后,對選中的m個數(shù)進(jìn)行全排列。而全排列的問題在之前的文章中已經(jīng)討論過了。

代碼實(shí)現(xiàn):

復(fù)制代碼 代碼如下:
func pailieResult(nums []int, m int) [][]int {
    //組合結(jié)果
    zuhe := zuheResult(nums, m)
    //保存最終排列結(jié)果
    result := make([][]int, 0)
    //遍歷組合結(jié)果,對每一項進(jìn)行全排列
    for _, v := range zuhe {
        p := quanPailie(v)
        result = append(result, p...)
    }
    return result
}
//n個數(shù)全排列
//如輸入[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.")
    }
    //如果只有一個數(shù),則直接返回
    if COUNT == 1 {
        return [][]int{nums}
    }
    //否則,將最后一個數(shù)插入到前面的排列數(shù)中的所有位置
    return insertItem(quanPailie(nums[:COUNT-1]), nums[COUNT-1])
}
func insertItem(res [][]int, insertNum int) [][]int {
    //保存結(jié)果的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插入到數(shù)組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
}

希望本文所述對大家Go語言程序設(shè)計有所幫助。

相關(guān)文章

  • 解讀go在遍歷map過程中刪除成員是否安全

    解讀go在遍歷map過程中刪除成員是否安全

    在Go語言中,通過for range遍歷map時可以安全地刪除當(dāng)前遍歷到的元素,因?yàn)楸闅v過程中的刪除操作不會影響遍歷的進(jìn)行,但需要注意,遍歷順序是不確定的,刪除元素不會導(dǎo)致程序錯誤,但可能會影響剩余元素的遍歷順序,在多線程環(huán)境下
    2024-09-09
  • 使用Go語言實(shí)現(xiàn)遠(yuǎn)程傳輸文件

    使用Go語言實(shí)現(xiàn)遠(yuǎn)程傳輸文件

    本文主要介紹如何利用Go語言實(shí)現(xiàn)遠(yuǎn)程傳輸文件的功能,有需要的小伙伴們可以參考學(xué)習(xí)。下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)。
    2016-08-08
  • golang雙鏈表的實(shí)現(xiàn)代碼示例

    golang雙鏈表的實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了golang雙鏈表的實(shí)現(xiàn)代碼示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Go語言數(shù)據(jù)結(jié)構(gòu)之插入排序示例詳解

    Go語言數(shù)據(jù)結(jié)構(gòu)之插入排序示例詳解

    這篇文章主要為大家介紹了Go語言數(shù)據(jù)結(jié)構(gòu)之插入排序示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • ?Go?語言實(shí)現(xiàn)?HTTP?文件上傳和下載

    ?Go?語言實(shí)現(xiàn)?HTTP?文件上傳和下載

    這篇文章主要介紹了Go語言實(shí)現(xiàn)HTTP文件上傳和下載,文章圍繞主題展開詳細(xì)的內(nèi)容戒殺,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • go?logger不侵入業(yè)務(wù)代碼使用slog替換zap并實(shí)現(xiàn)callerSkip詳解

    go?logger不侵入業(yè)務(wù)代碼使用slog替換zap并實(shí)現(xiàn)callerSkip詳解

    這篇文章主要為大家介紹了go?logger不侵入業(yè)務(wù)代碼使用slog替換zap并實(shí)現(xiàn)callerSkip詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 利用golang進(jìn)行OpenCV學(xué)習(xí)和開發(fā)的步驟

    利用golang進(jìn)行OpenCV學(xué)習(xí)和開發(fā)的步驟

    目前,OpenCV逐步成為一個通用的基礎(chǔ)研究和產(chǎn)品開發(fā)平臺,下面這篇文章主要給大家介紹了關(guān)于利用golang進(jìn)行OpenCV學(xué)習(xí)和開發(fā)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-09-09
  • GoFrame框架ORM原生方法對象操作開箱體驗(yàn)

    GoFrame框架ORM原生方法對象操作開箱體驗(yàn)

    這篇文章主要為大家介紹了GoFrame框架ORM原生方法對象操作的開箱體驗(yàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go??import _ 下劃線使用

    Go??import _ 下劃線使用

    這篇文章主要為大家介紹了Go??import下劃線_使用小技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 深度剖析Golang中的數(shù)組,字符串和切片

    深度剖析Golang中的數(shù)組,字符串和切片

    Golang 是一種以簡潔性、并發(fā)性和性能而著稱的編程語言。其重要特性之一是能夠處理數(shù)組、字符串和切片等數(shù)據(jù)類型。本篇文章將深入討論這些數(shù)據(jù)類型,并探討如何在代碼中使用它們
    2023-04-04

最新評論