成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

有多少種硬幣組合——找出獨(dú)特子數(shù)組之和

xiaoqibTn / 2148人閱讀

摘要:另外,我們還需要將所有硬幣組合起來,組成一個(gè)新的數(shù)組,其中包含了所有的硬幣。比如硬幣數(shù)組,和代表其數(shù)量的數(shù)組,組合成。

寫在前面的自我檢討

這道題的解法,剛開始我自己做的并不算是一個(gè)很好的解法,只能說題目是做出來了,但過程中的計(jì)算有大量的重復(fù)計(jì)算,導(dǎo)致函數(shù)復(fù)雜度直逼O(n^n)。查閱資料之后便有了一個(gè)改良版。感謝這篇文章Find all distinct subset (or subsequence) sums of an array!

背景

最近因?yàn)橐恍┰?,做了幾道“?jiǎn)單”的算法題。今天要講的便是其中的一道題:如果你有一個(gè)硬幣數(shù)組和一個(gè)代表其數(shù)量的數(shù)組,如何得到一共有多少種不同組合所得的和?

分析

比如:硬幣數(shù)組[10, 50, 100],和代表其數(shù)量的數(shù)組[1, 2, 1]就表示這里一共有三種硬幣,1枚10分,2枚50分和1枚100分硬幣。那么其可能的排列組合則包括

10 = 10

50 = 50

100 = 100

10 + 50 = 60

10 + 100 = 110

50 + 50 = 100

50 + 100 = 150

10 + 50 + 50 = 110

10 + 50 + 100 = 160

50 + 50 + 100 = 200

10 + 50 + 50 + 100 = 210

則,不重復(fù)的值則包括加黑的部分,一共是9個(gè)。

而我們現(xiàn)在的問題便是,輸入兩個(gè)數(shù)組:硬幣數(shù)組和代表其數(shù)量的數(shù)組,得到一個(gè)整數(shù)的返回值。

實(shí)際操作 第一步 定義輸入與輸出

根據(jù)分析,函數(shù)的輸入與輸出應(yīng)該規(guī)定如下。

/**
 * Count number of 
 * @param {Array} coins array contains coins with different values
 * @param {Array} counts array contains corresponding counts of different coins
 * @returns {Number} The count of distinct sums
 */
function countDistinctSum(coins, counts) {
    // Implementation
}
第二步 初始化變量和定義函數(shù)結(jié)構(gòu)

首先,我們應(yīng)該先做一個(gè)檢查,如果coins的長(zhǎng)度跟counts的長(zhǎng)度并不相等的話,則函數(shù)不應(yīng)該繼續(xù)處理,而是應(yīng)該返回一個(gè)錯(cuò)誤值。暫且定為-1吧。

然后,我們采用key value pair的形式來儲(chǔ)存不同和(sum)的數(shù)量。所以我們必須有一個(gè)名叫result的對(duì)象。當(dāng)然,其中并沒有任何的key。在函數(shù)運(yùn)行必要的計(jì)算之后,再返回result的key的數(shù)量作為最后的答案。

另外,我們還需要將所有硬幣組合起來,組成一個(gè)新的數(shù)組coinList,其中包含了所有的硬幣。比如:硬幣數(shù)組[10, 50, 100],和代表其數(shù)量的數(shù)組[1, 2, 1],組合成[10, 50, 50, 100]。這一部分用兩個(gè)for loop輕松搞定。

代碼如下:

function countDistinctSum(coins, counts) {
    if(coins.length !== counts.length) {
        return -1;
    }

    const results = {};
    const coinList = [];

    for(let i = 0; i < coins.length; i++){
        for(let j = 0; j < counts[i]; j++) {
            coinList.push(coins[i]);
        }
    }

    processList(coinList, coinList.length, 0, 0, results);

    return Object.keys(results).length - 1; // Remove the empty 0 coin element
}
第三步 處理coinList

當(dāng)我們得到一個(gè)coinList之后,接下來我們便要處理這個(gè)數(shù)組,將其內(nèi)部的元素全都排列一遍。比如,[10, 50, 100]就有以下排列方法。

[10]

[10, 50]

[10, 100]

[10, 50, 100]

[50]

[50, 100]

[100]

這時(shí),我便考慮使用遞歸法(recursive method)來解決這個(gè)問題。

函數(shù)接受兩個(gè)輸入

results用來儲(chǔ)存已經(jīng)有的sum

n用來儲(chǔ)存硬幣數(shù)組的長(zhǎng)度

sum用來儲(chǔ)存臨時(shí)已經(jīng)疊加的和

currentIndex用來記錄當(dāng)前遍歷到的索引

coinList用來輸入當(dāng)下數(shù)組里的硬幣元素。

設(shè)置出口條件

當(dāng)currentIndex大于coinList的長(zhǎng)度時(shí),返回。

當(dāng)currentIndex等于coinList的長(zhǎng)度時(shí),調(diào)用addToResults函數(shù)(下一步講解)然后返回。

遞歸函數(shù)

processList()會(huì)被遞歸兩次,這兩者之間的帶入?yún)?shù)區(qū)別只有sum的不同而已

第一個(gè)processList()將帶入sum加上當(dāng)下的coin值,達(dá)到計(jì)算累計(jì)的效果。比如:[10, 50, 50, 100]一路加到最后成為210。

第二個(gè)processList()將之帶入當(dāng)下的sum值去到下一個(gè)遞歸。隨著index的增加,該sum值會(huì)將一直被保留直到最終被加入result,它也將實(shí)現(xiàn)跳躍相加的方法。比如:[10, 50, 50, 100]其中的10 + 100就可以在這個(gè)遞歸中實(shí)現(xiàn)。

代碼如下:

/**
 * Recursive function to collect all the sums from all combinations
 * @param {Array} coinList array of coins
 * @param {Number} n the length of coin array
 * @param {Number} sum the current accumulated value
 * @param {Number} currentIndex the current processing index in the coin array
 * @param {Object} results existing result object brought into recursive function for recording sum
 */
function processList(coinList, n, sum, currentIndex, results) {
    if(currentIndex > n) {
        return;
    }

    if(currentIndex === n){
        addToResults(results, sum);
        return;
    }

    processList(coinList, n, sum + coinList[currentIndex], currentIndex + 1, results);
    processList(coinList, n, sum, currentIndex + 1, results);
}
第四步 addToResults函數(shù)

因?yàn)?b>result本身是空的,當(dāng)我們算出一個(gè)和是result里沒有的key的話,必須初始化這個(gè)key,使其值為1。反之,則只需要在其值上加1便可。

代碼如下:

/**
 * Add the number to results as a key
 * @param {Object} results 
 * @param {Number} number 
 */
function addToResults(results, number) {
    if(results[number]) {
        results[number]++;
    } else {
        results[number] = 1;
    }
}
大功告成!

完整代碼:

/**
 * Count number of 
 * @param {Array} coins array contains coins with different values
 * @param {Array} counts array contains corresponding counts of different coins
 * @returns {Number} The count of distinct sums
 */
function countDistinctSum(coins, counts) {
    if(coins.length !== counts.length) {
        return -1;
    }

    const results = {};
    const coinList = [];

    for(let i = 0; i < coins.length; i++){
        for(let j = 0; j < counts[i]; j++) {
            coinList.push(coins[i]);
        }
    }

    processList(coinList, coinList.length, 0, 0, results);

    return Object.keys(results).length - 1; // Remove the empty 0 coin element
}

/**
 * Recursive function to collect all the sums from all combinations
 * @param {Array} coinList array of coins
 * @param {Number} n the length of coin array
 * @param {Number} sum the current accumulated value
 * @param {Number} currentIndex the current processing index in the coin array
 * @param {Object} results existing result object brought into recursive function for recording sum
 */
function processList(coinList, n, sum, currentIndex, results) {
    if(currentIndex > n) {
        return;
    }

    if(currentIndex === n){
        addToResults(results, sum);
        return;
    }

    processList(coinList, n, sum + coinList[currentIndex], currentIndex + 1, results);
    processList(coinList, n, sum, currentIndex + 1, results);
}

/**
 * Add the number to results as a key
 * @param {Object} results 
 * @param {Number} number 
 */
function addToResults(results, number) {
    if(results[number]) {
        results[number]++;
    } else {
        results[number] = 1;
    }
}

測(cè)試:

const a = [10, 50, 100];
const b = [1, 2, 1];

console.log("Result:", countDistinctSum(a, b)) // Result: 9

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98739.html

相關(guān)文章

  • 多少硬幣組合,更優(yōu)解法

    摘要:寫在前面的自我檢討上周我發(fā)布了一篇博文有多少種硬幣組合找出獨(dú)特子數(shù)組之和,是關(guān)于有多少種硬幣組合的算法題的解法。假如,現(xiàn)在我們只有一個(gè)硬幣,分。則可能性只有種,那就是。 寫在前面的自我檢討 v2 上周我發(fā)布了一篇博文有多少種硬幣組合——找出獨(dú)特子數(shù)組之和,是關(guān)于有多少種硬幣組合的算法題的解法。雖然算法本身能夠給出一個(gè)正確答案,可是仔細(xì)想來,我卻沒辦法給出一個(gè)簡(jiǎn)單直接的解釋為什么這樣跑可...

    williamwen1986 評(píng)論0 收藏0
  • 理解CKB的Cell模型

    摘要:交易依然表示狀態(tài)的變化遷移。這樣一個(gè)模型的特點(diǎn)是狀態(tài)是第一性的所有者是狀態(tài)的屬性,每一份狀態(tài)只有一個(gè)所有者狀態(tài)不斷的被銷毀和創(chuàng)建。值得指出的是,的編程模型之所以強(qiáng)大,更多是因?yàn)樗袪顟B(tài),而不是因?yàn)樗挠邢迗D靈完備。 在設(shè)計(jì) CKB 的時(shí)候,我們想要解決三個(gè)方面的問題: 狀態(tài)爆炸引起的公地悲劇及去中心化的喪失;計(jì)算和驗(yàn)證耦合在了一起使得無論是計(jì)算還是驗(yàn)證都失去了靈活性,難以擴(kuò)展;交易與價(jià)...

    henry14 評(píng)論0 收藏0
  • 對(duì)比特幣的繼承與創(chuàng)新!深入理解公鏈 CKB 的 Cell 模型

    摘要:為了理解底層公鏈的模型,我們前置了幾篇概念性文章,講述了我們應(yīng)該以狀態(tài)為中心設(shè)計(jì)區(qū)塊鏈系統(tǒng)的,以及這么做帶來的好處。交易依然表示狀態(tài)的變化遷移。 為了理解底層公鏈 CKB 的 Cell 模型,我們前置了幾篇概念性文章,講述了我們應(yīng)該以狀態(tài)為中心設(shè)計(jì)區(qū)塊鏈系統(tǒng)的,以及這么做帶來的好處。并且在上一篇文章中,詳細(xì)分析了比特幣 UTXO 模型和以太坊的 Account 模型,以及進(jìn)行了對(duì)比分析...

    ruicbAndroid 評(píng)論0 收藏0
  • 前端也需要好好的精進(jìn)自己的算法

    摘要:算法前端發(fā)展的再快,也不要忘記精進(jìn)自己的算法,算法是靈魂和核心。我會(huì)把我刷過的算法題總結(jié)歸類,不斷完善。 算法 前端發(fā)展的再快,也不要忘記精進(jìn)自己的算法,算法是靈魂和核心。我會(huì)把我刷過的算法題總結(jié)歸類,不斷完善。歡迎大家關(guān)注。 數(shù)組和堆棧 數(shù)組去重 旋轉(zhuǎn)數(shù)組 如何快速找出兩個(gè)數(shù)之和等于某一個(gè)值的兩個(gè)數(shù)? 快排 排序算法大總結(jié) 快速找到數(shù)組中的最大值 多維數(shù)組的展開 二分查找 有效的括...

    hersion 評(píng)論0 收藏0
  • JavaScript 編程精解 中文第三版 十六、項(xiàng)目:平臺(tái)游戲

    摘要:來源編程精解中文第三版翻譯項(xiàng)目原文譯者飛龍協(xié)議自豪地采用谷歌翻譯部分參考了編程精解第版所有現(xiàn)實(shí)都是游戲。黑色的方塊表示玩家,玩家任務(wù)是收集黃色的方塊硬幣,同時(shí)避免碰到紅色素材巖漿。網(wǎng)格中的元素可能是空氣固體或巖漿。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項(xiàng)目原文:Project: A Platform Game 譯者:飛龍 協(xié)議:CC BY-NC-SA...

    wayneli 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<