DP in Linear Structures & Real Result

Summary

Some problems require returning real result not just a number.

To do this, a good method is that we create another table to store the optimal choices we made on each state.

To return any optimal result, the choice table will be as large as the alg table. The result can we achieved by a loop.

The return all the results, the choice table needs one more dimension (a vector) to store all optimal choices at each state. Results could be retrieved by backtracking.

Details

Return all Longest Common Subsequence

The length of the LCS is not difficult.

    \[alg[i][j] = max(1 + alg[i + 1][j + 1]\ if a[i] == b[j],  alg[i][j + 1], alg[i + 1][j])\]

We could use another 3D vector to store the choices we made at each state and do backtracking to get all LCS strings.

// choice
vector<vector<vector<int>>> choice;
for (int i = m - 1; i >= 0; --i) {
 for (int i = m - 1; i >= 0; --i) {
    for (int j = n - 1; j >= 0; --j) {
        int choice1 = 0, choice2, choice3;
        if (a[i] == b[j]) {
            choice1 = 1 + alg[i + 1][j + 1];
        } 
        choice2 = alg[i][j + 1];
        choice3 = alg[i + 1][j];
        int max_ = max(choice1, max(choice2, choice3));
        if (max_ == choice1) {
            choice[i][j].push_back(1);
        }
        if (max_ == choice2) {
            choice[i][j].push_back(2);
        }
        if (max_ == choice3) {
            choice[i][j].push_back(3);
        }
        alg[i][j] = max_;
    }
}

LC 1449. Form Largest Integer With Digits That Add up to Target

The problem is a typical knapsack problem. It requires that you choose as many as possible digits that cost sums up to target. Among the results with the same length, choose the lexicographically largest one.

The problem can be solved by a typical DP which stores the optimal solution at each state as a string. But by introducing string comparison, the worst complexity will be O(9*target^2).

// reverse cost, so that it goes from digit 9 to 1
alg[i][j] = max_ {
  1. alg[i + 1][j]
  2. "10 - i" + alg[i][j - cost[i]]
}
// alg[10][0] = ""
// max_ first compares length, then lexicographic order

However, we could do better by storing the length and greedily choose the larger digit at each state. Normally we use another table choice to record the optimal choices we made at each state.

alg[i][j] = max_ {
  1. alg[i + 1][j]
  2. 1 + alg[i][j - cost[i]]
}
choice[i][j] = {
  1. {false} if choose alg[i + 1][j] at alg[i][j]
  2. {true}  if choose alg[i][j - cost[i]] at alg[i][j]
  3. {false, true} if both are equal
}
// i = 1, j = target,
if choice[i][j] == {false, true}:
  we add this digit first since the digit (10 - i) is larger
  j -= cost[i]
else:
  choose what is in choice[i][j]

Leave a Reply

Your email address will not be published. Required fields are marked *