Lecture 23: Profits and Weighted Intervals

$ \def\opt{ {\mathrm{opt}} } $

COSC 311 Algorithms, Fall 2022

Overview

  1. Profit Maximization via Dynamic Programming
  2. Weighted Interval Scheduling

Profit Maximization

Input. Array $a$ of size $n$

  • $a[i] = $ price of Alphabet stock on day $i$

Output. Indices $b$ (buy) and $s$ (sell) with $1 \leq b \leq s \leq n$ that maximize profit

  • $p = a[s] - a[b]$

Another (Recursive) Procedure?

  • consider last day, $n$
  • two cases for optimal solution:
    1. max profit achieved by selling on day $n$
    2. max profit achieved by selling before day $n$

Questions.

  1. In case 1, how should we determine buy date?

    • find minimum price in $a[1..n]$
  2. In case 2, how should we compute max profit?

    • recursively find max profit for $a[1..n-1]$

Recursive Procedure

  MaxProfit(a, n):
    if n = 1 then return 0
    min <- FindMin(a, n)
    max <- MaxProfit(a, n-1)
    return max(a[n] - min, max)

Running time?

  • $\Theta(n^2)$
  • $n$ method calls of sizes $n, n-1, n-2, \ldots, 1$
  • running time is $\Theta(n + (n-1) + \cdots + 1) = \Theta(n^2)$

Memoizing MaxProfit

Create two arrays:

  1. min[i] stores minimum value in a[1..i]
  2. max[i] stores maximum profit achievable by selling up to time i

Question. How to update these arrays?

Example

Memoized Maximum Profit

  MMaxProfit(a):
    initialize arrays min, max 
    min[1] <- a[1]
    max[1] <- 0
    for i from 2 to n do
      min[i] <- Min(min[i-1], a[i])
      max[i] <- Max(max[i-1], a[i] - min[i])
    endfor
    return max[n]

Correctness

Claim. For every $i$, max[i] stores the maximum profit achievable by selling on a day $s \leq i$.

Proof. Induction on $i$…

Running Time?

  MMaxProfit(a):
    initialize arrays min, max 
    min[1] <- a[1]
    max[1] <- 0
    for i from 2 to n do
      min[i] <- Min(min[i-1], a[i])
      max[i] <- Max(max[i-1], a[i] - min[i])
    endfor
    return max[n]

Optimization

Can do without arrays for min and max

  MMaxProfit(a):
    min <- a[1]
    max <- 0
    for i from 2 to n do
      min <- Min(min, a[i])
      max <- Max(max, a[i] - min)
    endfor
    return max[n]

Exercise

Update MMaxProfit to return the buy/sell days in addition to the maximum achievable profit.

Weighted Interval Scheduling

Previously

Interval Scheduling:

Input. A set $R$ of $n$ intervals $r_1 = [s_1, t_1], r_2 = [s_2, t_2], \ldots, r_n = [s_n, t_n]$

Output. A collection of intervals from $R$ that is:

  1. feasible no two intervals overlap
  2. maximum the largest possible feasible collection

Maximum feasible collection can be found in $O(n \log n)$ time using a greedy algorithm

Today

Weighted Interval Scheduling:

Input.

  1. A set $R$ of $n$ intervals $r_1 = [s_1, t_1], r_2 = [s_2, t_2], \ldots, r_n = [s_n, t_n]$
  2. For each interval $r \in R$, a weight $w(r) > 0$
    • e.g., weight = profit from serving request $r$

Output. A collection of intervals from $R$ that is

  1. feasible no two intervals overlap
  2. maximum weight choice maximizes sum of $w(r)$ for chosen $r$

Note: equivalent to (unweighted) interval scheduling when all weights are the same

Example

Exercise

Construct an example for which the greedy algorithm for unweighted interval scheduling does not find a maximum weight solution.

Pre-processing

  1. Sort intervals by end date
    • $[s_1, t_1], [s_2, t_2], \ldots, [s_n, t_n]$
    • $t_1 \leq t_2 \leq \cdots \leq t_n$
  2. For each interval $r_i = [s_i, t_i]$ define
    • $p[r_i] = r_j$ where $r_j$ is last interval with $t_j < s_i$

Optimal Solution Structure

Two cases for optimal solution $\opt$:

  1. last interval $r_n$ is in $\opt$
  2. last interval $r_n$ is not in $\opt$

Questions.

  1. What is the structure of optimal solution in case 1?

  2. What is the structure of optimal solution in case 2?

A Recursive Solution

  MaxWeightSchedule(w, p, n):
    if n = 0 then return 0
    opt-n <- w[n] + MaxWeightSchedule(w, p, p[n])
    opt-no-n <- MaxWeightSchedule(w, p, n-1)
    return Max(opt-n, opt-no-n)

Correctness?

Running Time?

  MaxWeightSchedule(w, p, n):
    if n = 0 then return 0
    opt-n <- w[n] + MaxWeightSchedule(w, p, p[n])
    opt-no-n <- MaxWeightSchedule(w, p, n-1)
    return Max(opt-n, opt-no-n)

Recursion to Iteration

Idea. Store array max:

  • max[i] is maximum weight of schedule consisting of intervals $r_1, r_2, \ldots, r_i$

Question. How to initialize/update max values?

Iterative Solution

  IMaxWeightSchedule(w, p)
    max <- new array of size n+1 
    max[0] <- 0
    for i = 1 up to n do
      max[i] <- Max(w[i] + max[p[i]], max[i-1])
    endfor
    return max[n]

Correctness:

  • same argument as recursive solution

Running Time?

Overall Running Time?

Steps: (assume $n$ intervals)

  1. Sort intervals by end time

  2. Compute array p

  3. Run IMaxWeightSchedule(w, p)

Total?

Exercise

Update IMaxWeightSchedule to return the actual schedule of maximum weight, not just the weight itself.

Next Time

  • Sequence Alignment