Maximum Coins Value

这个题来自于《算法设计与分析基础第3版》8.1例1. 是一个很典型的动归问题。
给定n个硬币,从中选出任意多个,但是不能连续选择两个相邻的硬币,例如选了第i个,那么就不能再选第i+1个了。问怎么取才能得到的硬币的value最大。

Discussion

上述的最大金额用F[n]表示,我们可以选择包括最后一个硬币和不包括最后一个硬币,两种情况的最大值就是F[n]了。
很容易写出递推公式F[n] = max{F[n-2]+coins[n-1], F[n-1]}, n>2
初始情况F[0] = 0, F[1] = coins[0]

写出来递推公式以后就完全不难了,跟Fibonacci的公式很像了,算法上是一模一样的。

Solution

//O(n) run time
//O(n) space
 int maxCoinValues(vector<int> &coins) {
     int n = coins.size();
     if (n == 0) return 0;
     vector<int> f(n + 1, 0);
     f[1] = coins[0];
     int a = 0;
     int b = coins[0];
     for (int i = 2; i <= n; i++) {
         f[i] = max(f[i - 1], f[i - 2] + coins[i - 1]);
     }
     return result;
 }

improve to save space

//O(n) run time
//O(1) space
 int maxCoinValues(vector<int> &coins) {
     int n = coins.size();
     if (n == 0) return 0;
     f[1] = coins[0];
     int a = 0;
     int b = coins[0];
     int result = b;
     for (int i = 2; i <= n; i++) {
         result = max(b, a + coins[i - 1]);
         a = b;
         b = result;
     }
     return result;
 }

Follow up

如果是要求那些coins组成了当前的最大值呢?增加一个回溯的过程,看哪些硬币被选出来了。

  vector<int> maxCoinValues2(vector<int> &coins) {
     int n = coins.size();
     vector<int> f(n + 1, 0);
     f[1] = coins[0];
     vector<int> result;
     for (int i = 2; i <= n; i++) {
         f[i] = max(f[i - 1], f[i - 2] + coins[i - 1]);    
     }
     //backtracking to find out which coin is selected
     int i = n;
     while (i >= 2) {
         //f[i] = max(f[i-1], f[i-2]+a[i-1];
         if (f[i - 2] + coins[i - 1] > f[i - 1]) {
             result.emplace_back(i - 1);
             i = i - 2;
         }
         else {
             if (i == 2) {
                 result.emplace_back(0); //coins[1] is not included, so coins[0] must be one part of result;
             }
             i--;
         }
     }
     return result;
 }

results matching ""

    No results matching ""