classSolution {public:intchange(int amount,vector<int>& coins) {returnenumerate(amount, coins,0); }private:intenumerate(int amount,vector<int>& coins,int curIdx){if(amount ==0)return1;if(coins.empty() || curIdx >=coins.size())return0; // Use the coin[i]int way1 =0;if(coins[curIdx] <= amount) way1 =enumerate(amount-coins[curIdx], coins, curIdx); // Do not use coin[i]int way2 =enumerate(amount, coins, curIdx+1);return way1+way2; }};
這個解法不意外地會 TLE。
解法二 - 暴力法 + memoization
我們可以用一個 2D array 來記錄已經計算過的結果,實作如下:
classSolution {public:intchange(int amount,vector<int>& coins) { vector<vector<int>>memo(coins.size(),vector<int>(amount+1,-1));returnenumerate(amount, coins,0, memo); }private:intenumerate(int amount,vector<int>& coins,int curIdx,vector<vector<int>>& memo){if(amount ==0)return1;if(coins.empty() || curIdx >=coins.size())return0;if(memo[curIdx][amount] !=-1)returnmemo[curIdx][amount]; // Use the coin[i]int way1 =0;if(coins[curIdx] <= amount) way1 =enumerate(amount-coins[curIdx], coins, curIdx, memo); // Do not use coin[i]int way2 =enumerate(amount, coins, curIdx+1, memo);memo[curIdx][amount] = way1+way2; returnmemo[curIdx][amount]; }};
雖然可以過,但效率頗差:
Runtime: 68 ms, faster than 10.27% of C++ online submissions for Coin Change 2. Memory Usage: 22.5 MB, less than 14.29% of C++ online submissions for Coin Change 2.
解法三 - DP
經過上面的思考過程,要寫出 recurrence formula 就輕鬆不少,首先定義一下 subproblem:
classSolution {public:intchange(int amount,vector<int>& coins) {if(coins.empty() && amount <=0)return1;if(amount >0&&coins.empty())return0; // Init // amount == 0, there's one way to have this amount vector<int>dp(amount+1,0);dp[0] =1; // Building DP tablefor(int c=0; c<coins.size(); c++) {for(int a=0; a<=amount; a++) {dp[a] =dp[a] + (coins[c] <= a ?dp[a-coins[c]] :0); } }returndp[amount]; }};
效率提升不少:
Runtime: 12 ms, faster than 47.66% of C++ online submissions for Coin Change 2. Memory Usage: 8.6 MB, less than 100.00% of C++ online submissions for Coin Change 2.