close

一開始先發個牢騷好了

雖然說開履歷才不到一個禮拜,也還沒開始面試

不過依照以往的經驗,開始找之後就是信心要開始下滑的時候了

上網找了一些職缺,發現我想去的公司條件都要求好多,而且都一堆人在投

想想也是很正常的嘛,好公司大家都想進,進不進的去就看個人能力和造化了

與其在那邊覺得自己實力不夠,不如就從現在開始好好加強自己的能力吧

如果說寫網誌能夠促進自己學習,那就盡量寫吧~

 

今天這題是一個換錢的題目

給一個陣列表示有哪些幣值,然後給你一個數字

算出用哪一個方法可以用最少的硬幣數量湊出那個數字,然後回傳那個數量,舉例來說:

Input: coins = [1, 2, 5], amount = 11
Output: 3 
Explanation: 11 = 5 + 5 + 1

如果連一種方式都湊不出來,回傳-1

 

今天這題略難一點

至少對我來說是啦...

如果沒什麼概念,大概完全不知道怎麼辦吧

 

Sol:

這題主要是要用到一種Dynamic Programming的概念

有興趣可以去google一下

大概的想法就是藉由記錄算出的結果,然後一直往目標去算,利用記錄的結果去算出目標

這樣可以減少過程中很多不必要計算

最簡單的例子... 像費伯納西數列就有點類似的概念

記住前一次算出來的數值,來計算現在要計算的數值,而不是每次都要從頭算

 

但是這題又比較不一樣,不只要記住前一次的結果,而是要記住前面全部的結果

因為沒有辦法知道會有什麼幣值,所以只能全部記住了

 

大概的code是這樣,附上註解:

    int coinChange(vector<int>& coins, int amount) {
        int dp[amount + 1];  // 初始化一個大小為amount+1的陣列,用來記錄每一個數值最少要用多少硬幣組成
        
        dp[0] = 0;  // 0就是0
        for (int i = 1; i <= amount; ++i)
        {
            dp[i] = -1;  // 其餘的初始值為-1,表示沒有組合能夠組出這個數值
        }
        
        for (int i = 0; i <= amount; ++i)  // 從最小的值開始往上算
        {
            int min = INT_MAX;
            
            for (int coin : coins)  // 計算每一種幣值
            {
                if (i - coin >= 0 && dp[i - coin] != -1)  // 這邊是關鍵,dp[i - coin]就是表示i-coin那個數值最少能用多少硬幣組成,如果等於-1就表示組不出來,所以i也不會組出來
                {
                    int tmp = dp[i - coin] + 1;  // 多加一個硬幣,所以加1
                    
                    if (tmp < min)  // 比出最小的組成數量
                    {
                        min = tmp;
                    }
                }
            }
            
            if (min != INT_MAX)
            {
                dp[i] = min;  // 如果min不為INT_MAX,表示i是能被組出來的,記錄在dp[i]裡面
            }
        }
        
        return dp[amount];  // 結束上面的計算後,dp[amount]就是用最少硬幣組成amount的答案
    }

關鍵就是在那個dp,要從下往上記錄那些值

 

另外也可以用遞迴的方式來做,不過我個人是不太推薦啦

因為實際上兩種方式的過程是一樣的,都是由小的值往上算(廢話不然怎麼算...)

只是思考的方式不一樣,寫成code之後也長得不一樣了

遞迴的話看起來是從上往下推的,code大概是這樣:

    vector<int> m_coins;
    
    int minCoinAmount(int amount, vector<int>& memo)
    {
        if (amount == 0)
            return 0;
        else if (amount < 0)
            return -1;
        
        if (memo[amount] != 0)
            return memo[amount];
        
        int res = INT_MAX;
        
        for (int coin : m_coins)
        {
            int minCoin = minCoinAmount(amount - coin, memo);  // 差別就是這個,他會把amount-coin拿去往下算,得到結果後再傳回來
            
            if (minCoin >= 0 && minCoin < res)
                res = minCoin + 1;
        }
        
        memo[amount] = (res == INT_MAX) ? -1 : res;
        
        return memo[amount];
    }
    
    int coinChange(vector<int>& coins, int amount) {
        vector<int> memo(amount + 1, 0);
        m_coins = coins;
        
        return minCoinAmount(amount, memo);
    }

 

其實大概看code也能發現兩個作法概念是一樣的,所以就看想怎麼做而已

這個技巧可以應用在很多地方,我覺得可以好好琢磨一下

比如說旅遊交通金錢的規劃(之後會有相關的題目)之類的

那麼這題就到這邊了~ 下題再見~

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 頁頁頁六滴 的頭像
    頁頁頁六滴

    人森很精彩,所以要把所有事情都記起來=ˇ=

    頁頁頁六滴 發表在 痞客邦 留言(0) 人氣()