A family of problems on a price array , distinguished by how many transactions are allowed.

One transaction —

Buy once, sell once, later.

long long maxProfit1(const vector<int>& p) {
    long long best = 0; int minSoFar = p[0];
    for (int x : p) {
        best = max(best, (long long)x - minSoFar);
        minSoFar = min(minSoFar, x);
    }
    return best;
}

This is exactly Kadane on the difference array — the maximum subarray of daily changes.

Unlimited transactions —

Sum every upward move:

long long maxProfitInf(const vector<int>& p) {
    long long total = 0;
    for (int i = 1; i < (int)p.size(); i++)
        total += max(0, p[i] - p[i-1]);
    return total;
}

Any sequence of buys and sells telescopes into a sum of consecutive differences, so taking every positive one is optimal — a one-line exchange argument.

At most transactions —

long long maxProfitK(const vector<int>& p, int k) {
    int n = p.size();
    if (k >= n / 2) return maxProfitInf(p);            // unlimited case
    vector<long long> buy(k + 1, LLONG_MIN / 2), sell(k + 1, 0);
    for (int x : p)
        for (int j = 1; j <= k; j++) {
            buy[j]  = max(buy[j],  sell[j-1] - x);     // hold after j-th buy
            sell[j] = max(sell[j], buy[j] + x);        // done after j-th sell
        }
    return sell[k];
}

The k >= n/2 shortcut matters: with enough transactions allowed, the constraint is vacuous, and it prevents an blowup when .

The state-machine view

Every variant is a small DP over “how many transactions used” × “holding or not”:

       buy                sell
free ------> holding ------------> free (one more transaction used)

Adding a rule adds a state or an edge:

RuleChange
Cooldown of 1 day after sellingadd a cooldown state
Transaction fee subtract on each sell
At most transactionsindex the states by
Must hold daysindex by days held
Short selling allowedadd a symmetric short state

Once you draw the state machine, the code is mechanical. This is the clearest small example of DP as a state machine.

Huge — the Aliens trick

For up to with large, the DP is too slow. But the profit as a function of is concave (each extra transaction adds less), so Lagrangian relaxation applies:

  1. Charge a penalty per transaction.
  2. Solve the unlimited version with that penalty in .
  3. Binary search until exactly transactions are used.
  4. The answer is .

— independent of . This is the canonical worked example for the Aliens trick, and worth studying for that reason alone.

The variant table

VariantMethodCost
One transactionrunning minimum
Unlimitedsum of positive differences
At most 2the DP, or forward/backward passes
At most state DP
At most , hugeAliens trick
With cooldown3-state DP
With a fee2-state DP
Best time to buy and sell with short selling4-state DP

At most 2 transactions in

Two passes: left[i] = best profit using one transaction in ; right[i] = best in . Then . The same prefix/suffix decomposition solves many “split the array into two independent parts” problems.

Why it is worth knowing

Three techniques appear in one small problem family:

  1. Reduction to a known problem — one transaction is Kadane on differences.
  2. State-machine DP — the general framework, extended by adding states.
  3. Lagrangian relaxation — removing a “exactly ” constraint when the answer is concave in .

See also: Kadane’s Algorithm · Aliens Trick · Introduction to DP