IOS 算法(中級篇) ----- 零錢兌換 II

給你一個整數(shù)數(shù)組 coins 表示不同面額的硬幣,另給一個整數(shù) amount 表示總金額拒贱。
請你計算并返回可以湊成總金額的硬幣組合數(shù)宛徊。如果任何硬幣組合都無法湊出總金額,返回 0 逻澳。
假設(shè)每一種面額的硬幣有無限個闸天。
題目數(shù)據(jù)保證結(jié)果符合 32 位帶符號整數(shù)。

例子

輸入:amount = 5, coins = [1, 2, 5]
輸出:4
解釋:有四種方式可以湊成總金額:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
示例 2:

輸入:amount = 3, coins = [2]
輸出:0
解釋:只用面額 2 的硬幣不能湊成總金額 3 斜做。
示例 3:

輸入:amount = 10, coins = [10]
輸出:1

提示:

1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins 中的所有值 互不相同
0 <= amount <= 5000


解題思路

典型的動態(tài)規(guī)劃問題, 它利用了之前計算的結(jié)果來更新當前的結(jié)果苞氮,這是動態(tài)規(guī)劃的典型特點。

初始化: 我們創(chuàng)建一個數(shù)組 dp瓤逼,長度為 amount + 1笼吟,用來存儲每個金額對應(yīng)的組合數(shù)库物。
dp[0] 初始化為: 1,因為湊成金額 0, 只有一種贷帮,即不用任何硬幣艳狐。

遍歷硬幣: 我們遍歷給定的硬幣數(shù)組 coins。對于每個硬幣 coin皿桑,我們更新 dp 數(shù)組毫目。

更新 dp 數(shù)組:

  • 對于每個硬幣 coin,我們從 coin 開始遍歷 dp 數(shù)組诲侮,直到 amount镀虐。
  • 對于每個金額 i,我們更新 dp[i] 的值沟绪。
  • 更新規(guī)則是 dp[i] = dp[i] + dp[i - coin]刮便。這意味著湊成金額 i 的組合數(shù)等于之前計算的組合數(shù) (dp[i]) 加上湊成金額 i - coin 的組合數(shù) (dp[i - coin])

對于每個硬幣绽慈,我們可以選擇使用它或不使用它恨旱。如果我們選擇使用這個硬幣,那么問題就變成了湊成金額 i - coin 的組合數(shù)坝疼,而i - coin 金額組合數(shù)在之前的步驟中計算過了搜贤。

返回結(jié)果: 最后,dp[amount] 就是我們要求的結(jié)果钝凶,即湊成總金額 amount 的組合數(shù)仪芒。

代碼:

未翻譯版
    func change(_ amount: Int, _ coins: [Int]) -> Int {
        
        var dp = [Int](repeating: 0, count: amount + 1)
        dp[0] = 1

        for coin in coins {
            if coin > amount { return dp[amount] }
            for i in coin...amount {
                dp[i] += dp[i - coin]
            }
        }

        return dp[amount]
    }
翻譯版
    func change(_ amount: Int, _ coins: [Int]) -> Int {
        
        // 定義0 ~ amount 的可變數(shù)組, 代表 0 ~ 總金額 之間的所有情況
        var dp = [Int](repeating: 0, count: amount + 1)

        // 湊成總金額為0 的時候, 只有1種可能, 不掏
        dp[0] = 1

        // 遍歷硬幣數(shù)組
        for coin in coins {

            // 如果當前硬幣大于總金額, 直接返回 dp[amount]
            // 例如: coins = [2], amount = 1 這種
            // 或 coins = [2, 100, 101], amount = 3, 
            // 遍歷到 100 這種, 超過要求總金額, 沒必要繼續(xù)遍歷
            if coin > amount { return dp[amount] }

            // 遍歷 當前硬幣 ~ 總金額, 計算每種金額需要情況
            for i in coin...amount {

                // 湊成總金額 i 的方式
                // 等于原來的組合數(shù) 加上湊成總金額 i - coin 的組合數(shù)
                // 例如 coins = [1, 2, 3], amount = 5
                // dp = [1, 0, 0, 0, 0, 0] 數(shù)組下標為對應(yīng)總金額
                // 當 i = 1, 硬幣為1, 遍歷完
                // dp = [1, 1, 1, 1, 1, 1]
                // 總金額如果是 0, 1種情況
                // 總金額如果是 1, 1種情況
                // ...
                // 總金額如果是 5, 1種情況, 1+1+1+1+1

                // 當 i = 2, 硬幣為2, 須用2硬幣
                // 那么總金額為2的情況, 
                // 為當前總金額2組合數(shù)+總金額0組合數(shù)  2+0
                // 即 dp[2] + dp[0], 
                // dp[2] = dp[2] + dp[2 - 2] =  dp[2] + dp[0] 

                // 同理, 須用2硬幣, 總金額為3的情況 2+1 
                // 為當前總金額3組合數(shù)+總金額1組合數(shù)  即 dp[3] + dp[1]
                // dp[3] = dp[3] + dp[3 - 2] =  dp[3] + dp[1] 

                // 同理, 須用2硬幣, 總金額為4的情況 2+2
                // 為當前總金額4組合數(shù)+總金額2組合數(shù)  即 dp[4] + dp[2]
                // dp[4] = dp[4] + dp[4 - 2] =  dp[4] + dp[2] 

                // 同理, 須用2硬幣, 總金額為5的情況 2+3
                // 為當前總金額4組合數(shù)+總金額3組合數(shù)  即 dp[5] + dp[3]
                // dp[5] = dp[5] + dp[5 - 2] =  dp[5] + dp[3] 
                 
                dp[i] += dp[i - coin]
            }
        }


        // 返回湊成總金額情況
        return dp[amount]
    }
時間復(fù)雜度:

O(n * m),其中 n 是金額(amount)的大小耕陷,m 是硬幣種類(coins 數(shù)組的長度)的數(shù)量掂名。這是因為我們需要對每種硬幣進行遍歷,并且對每個金額從該硬幣面額到總金額進行更新哟沫。

空間復(fù)雜度:

O(n)饺蔑,其中 n 是金額(amount)的大小。我們需要一個長度為 n + 1 的數(shù)組來存儲從 0 到 n 的每個金額對應(yīng)的組合數(shù)嗜诀。

題目來源:力扣(LeetCode) 感謝力扣爸爸 :)
IOS 算法合集地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末猾警,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子裹虫,更是在濱河造成了極大的恐慌肿嘲,老刑警劉巖融击,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筑公,死亡現(xiàn)場離奇詭異,居然都是意外死亡尊浪,警方通過查閱死者的電腦和手機匣屡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門封救,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捣作,你說我怎么就攤上這事誉结。” “怎么了券躁?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵惩坑,是天一觀的道長。 經(jīng)常有香客問我也拜,道長以舒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任慢哈,我火速辦了婚禮蔓钟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘卵贱。我一直安慰自己滥沫,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布键俱。 她就那樣靜靜地躺著兰绣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪编振。 梳的紋絲不亂的頭發(fā)上狭魂,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音党觅,去河邊找鬼雌澄。 笑死,一個胖子當著我的面吹牛杯瞻,可吹牛的內(nèi)容都是我干的镐牺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼魁莉,長吁一口氣:“原來是場噩夢啊……” “哼睬涧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起旗唁,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤畦浓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后检疫,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讶请,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年屎媳,在試婚紗的時候發(fā)現(xiàn)自己被綠了夺溢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片论巍。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖风响,靈堂內(nèi)的尸體忽然破棺而出嘉汰,到底是詐尸還是另有隱情,我是刑警寧澤状勤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布鞋怀,位于F島的核電站,受9級特大地震影響持搜,放射性物質(zhì)發(fā)生泄漏接箫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一朵诫、第九天 我趴在偏房一處隱蔽的房頂上張望辛友。 院中可真熱鬧,春花似錦剪返、人聲如沸废累。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽邑滨。三九已至,卻和暖如春钱反,著一層夾襖步出監(jiān)牢的瞬間掖看,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工面哥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留哎壳,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓尚卫,卻偏偏與公主長得像归榕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吱涉,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容