Longest Increasing Subsequence (LIS)

Context: FIT2004_MOC · the credit-level classical DP problem, and the vault’s standing counterexample to “the answer is the last cell” Parent Framework: Dynamic Programming

Quick Revision

  • 🎯 Objective: the length of the longest increasing subsequence ending at position ➔ answer , not .
  • 📦 Core Components: subproblems ➔ each scans all earlier positions ⟹ time, space.
  • ⚡ Key Constraint: the subproblem must be anchored — “ending at ” — because a free-floating “LIS of ” cannot be extended, since it does not say what the last element is.

📝 How It Works

1. Why the Subproblem Must Be Anchored

  • The observation ➔ take an LIS ; every prefix of it is itself a longest increasing subsequence among those ending at position .
  • The proof shape ➔ if it were not longest, swapping in the longer one would give a longer LIS overall — contradiction. That is the optimal-substructure argument, and it is what forces the anchor.
  • What the anchor buys ➔ knowing the last element lets you test extendability with a single comparison ; without it there is nothing to compare against.
  • What the anchor costs ➔ the answer is no longer a single cell. is the LIS ending at the last element, and the true LIS need not include it ➔ scan the table.

2. The Recurrence

  • Read it aloud ➔ “element itself, plus the best chain I can hang it onto.”
  • The base is inside the general case ➔ the first clause is the edge case: no smaller predecessor exists, so (the singleton subsequence). Writing it as only is wrong — any can be a minimum-so-far.
  • Strict , not ➔ the problem says strictly increasing; silently solves the non-decreasing problem and duplicates get chained.
  • Answer ➔ .

3. Complexity, and Where Each Factor Comes From

  • Subproblems ➔ , one per position ⟹ auxiliary space (1-D MEMO ➔ Dynamic Programming §5).
  • Work per subproblem ➔ the inner scans every ⟹ .
  • Total ➔ time. The final scan adds and is dominated.
  • No best/worst split ➔ both loops are input-independent, so best average worst ; only the reconstruction length varies.

4. Reconstruction — Which Elements, Not Just How Many

  • Store the argmax ➔ pred[i] = the j that achieved the maximum, None when the edge case fired.
  • Start at the argmax of the whole table, not at — the single most common LIS bug.
  • Backtrack and reverse ➔ the same breadcrumb walk as Dijkstra’s previous ➔ Dynamic Programming §7.
  • Ties give different, equally valid answers ➔ state your tie-break rule (e.g. smallest ) before hand-tracing, exactly as for a MST trace.

5. LIS in Disguise — the Box-Stacking Reduction (applied P17)

  • Problem ➔ box types, each rectangular; a box may sit on another iff both base dimensions are strictly smaller; boxes may be rotated and reused. Maximise tower height.
  • Kill the rotation first ➔ make six copies of every box, one per orientation ⟹ boxes and no rotation logic. The constant vanishes into the bound.
  • Reuse becomes impossible for free ➔ base dimensions must strictly decrease going up, so no box type can recur; the copies make that automatic.
  • The recurrence is LIS with a 2-D order
  • Same shape, three substitutions ➔ “length ” becomes “height ”; the scalar test becomes the pair test ; the answer is still , never .
  • Cost ➔ subproblems scan .
  • The transferable move (LO1) ➔ longest chain under any strict partial order is LIS; recognising the order is the whole problem.

⚙️ Core Implementation

🔹 LIS with reconstruction

🔭 Beyond the lecture (not in the slides): LIS also has an solution that keeps the smallest possible tail for each achievable length and places each element by binary search. FIT2004's applied sheet asks for ; do not offer the faster one as the unit's method.

⚖️ Complexity

CaseTimeAuxiliary spaceTrigger
Best Average Worsttwo nested loops, no early exit — input-independent
Reconstruction pass for predthe chain is at most long
Box stacking (§5) boxes ⟹ the is a constant

📊 Exam Execution Trace & Applied Exercises

Manual Execution Trace

(the applied sheet’s instance). Tie-break: smallest .

Candidates with (best )
——

Final Extracted Output: at ; backtracking yields . The sheet’s is equally valid — the tie at between and is broken by the stated rule, and both give length .

  • Read the trap ➔ while : the table is not monotone, so the final scan is mandatory. Here the argmax happens to land on ; do not let that coincidence become a habit.
  • Read the shape ➔ every row is “my own element, plus the tallest chain among strictly smaller earlier elements” — the same sentence as box stacking with the order swapped.

Applied Exercise — turn a stacking problem into LIS (P17)

Problem: show that copies per box type make the “no reuse” rule automatic.

Final Extracted Output: the -copy formulation needs no reuse bookkeeping, and . The reusable move: enumerate the finitely many configurations of an object up front, and a constraint that looked stateful becomes a property of the ordering.

⚠️ Common Mistakes

  • 💡 Answer ➔ the anchored subproblem forces a scan; this is the single most-marked LIS error and the wrap-up flags it explicitly.
  • 💡 Defining as “the LIS of ” ➔ unanchored, so the recurrence cannot test extendability and the definition is unusable. Fix the definition, not the code.
  • 💡 Non-strict comparison ➔ answers a different problem; state strictly increasing in the subproblem sentence.
  • 💡 Quoting space as ➔ the MEMO is 1-D; the is the inner scan, i.e. time ➔ Dynamic Programming §5.
  • 💡 Reconstructing from alone without pred ➔ possible but fiddly; store the argmax, it is and free within the existing bound.

🧠 Active Recall