3.7.11 · HinglishAlgorithm Paradigms

DP problems — Longest Increasing Subsequence (LIS) — O(n²) and O(n log n)

1,768 words8 min readRead in English

3.7.11 · Coding › Algorithm Paradigms

Ek-line goal: Ek array diya gaya hai, usmein sabse lambi subsequence ki length nikalni hai (contiguous nahi!) jiske elements strictly increasing hों.


HUM KYA COMPUTE KAR RAHE HAIN?

Example: A = [10, 9, 2, 5, 3, 7, 101, 18] → LIS = [2, 3, 7, 101] ya [2, 3, 7, 18], length 4.


Approach 1 — DP in

for i in 0..n-1:
    dp[i] = 1
    for j in 0..i-1:
        if A[j] < A[i]:
            dp[i] = max(dp[i], dp[j] + 1)
answer = max(dp)

Cost: do nested loops → time, space.


Approach 2 — Patience sorting in

Figure — DP problems — Longest Increasing Subsequence (LIS) — O(n²) and O(n log n)

Forecast-then-Verify

Recall Answer padhne se pehle:

A=[0,1,0,3,2,3] ke liye LIS length kya hai aur ek aise subsequence ka example? Length 4: [0,1,2,3]. tails se check karo: [0]→[0,1]→ (0 replace karo)[0,1]→[0,1,3]→(3 ko 2 se replace karo)[0,1,2]→[0,1,2,3]. ✓


Flashcards

What is the difference between a subsequence and a subarray?
Subarray contiguous hota hai; subsequence elements ko reorder kiye bina delete karke banta hai (gaps ho sakte hain).
Define the DP state used in the O(n²) LIS solution.
dp[i] = longest increasing subsequence ki length jo exactly index i par end hoti hai.
State the O(n²) LIS recurrence.
dp[i] = 1 + max(0, {dp[j] : j<i and A[j]<A[i]}); answer = max over all dp[i].
Why is the final answer max(dp) and not dp[n-1]?
Kyunki LIS kisi bhi index par end ho sakti hai, zaroor nahi ki last wale par.
In the O(n log n) method, what does tails[k] store?
Length k+1 ki kisi bhi increasing subsequence ki sabse chhoti possible tail value.
Why is the tails array always strictly increasing?
Ek lambi chain ko kaat dene par ek chhoti tail wali chhoti chain milti hai, aur tails[k] woh sabse chhoti tail hai, isliye values length ke saath badhni chahiye.
For each new x in patience sorting, what do you do?
lower_bound se pehla tails[k] >= x dhundho; replace karo, ya x ko append karo agar x saari tails se bada ho.
Why use lower_bound (>=) instead of upper_bound (>) for strict LIS?
Taaki equal values ek fake lambi increasing chain na banayein; >= ise strictly increasing rakhta hai.
Does len(tails) equal the LIS length? Is tails the actual LIS?
len(tails) = sahi LIS length; lekin tails khud ek valid subsequence NAHI hai (ise recover karne ke liye predecessor pointers chahiye).
What are the time complexities of the two LIS methods?
O(n²) DP, aur O(n log n) tails par binary search ke saath.

Recall Feynman: ek 12-saal ke bachche ko samjhao

Socho cards ko face-up piles mein left se right rakh rahe ho. Rule: ek card sirf us pile par ja sakta hai agar woh us pile ke top card se bada ho, aur tum hamesha use sabse left wali pile par rakhte ho jahan woh fit ho — agar kahin fit nahi hota, toh right mein ek bilkul naya pile shuru karo. Jitne piles bante hain woh cards ki sabse lambi "hamesha barhti hui" line ki length hai jo tum chun sakte ho! Har pile ka top jitna ho sake utna chhota rakha jaata hai taaki baad mein zyada cards stack ho sakein. Woh "leftmost pile" choice hi binary search hai.


Connections

  • Dynamic Programming — LIS classic 1D DP-on-suffix/prefix pattern hai.
  • Binary Searchlower_bound O(n log n) speedup deta hai.
  • Patience Sorting — fast method ke peeche card-pile model.
  • Longest Common Subsequence (LCS) — LIS(A) = LCS(A, sorted-unique(A)).
  • Greedy Algorithms — sabse chhoti tails rakhna ek greedy exchange argument hai.
  • Russian Doll Envelopes — LIS par based ek 2D application.

Concept Map

works on

brute force

too slow, use

state

recurrence

two nested loops

answer

faster method

maintains

greedy binary search

smaller tail

LIS longest increasing subseq

Subsequence not contiguous

O 2^n subsequences

Approach 1 DP

dp i ends at index i

dp i = 1 + max dp j where A j < A i

O n^2 time

max over all dp i

Approach 2 patience sorting

tails k = smallest tail of length k+1

O n log n time

easier to extend later