A=[0,1,0,3,2,3], what's the LIS length and one such subsequence?
Length 4: [0,1,2,3]. Check with tails: [0]→[0,1]→ (replace 0)[0,1]→[0,1,3]→(replace 3 with 2)[0,1,2]→[0,1,2,3]. ✓
What is the difference between a subsequence and a subarray?
Subarray is contiguous; subsequence is formed by deleting elements without reordering (can have gaps).
Define the DP state used in the O(n²) LIS solution.
dp[i] = length of the longest increasing subsequence ending exactly at index i.
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]?
Because the LIS can end at any index, not necessarily the last one.
In the O(n log n) method, what does tails[k] store?
The smallest possible tail value of any increasing subsequence of length k+1.
Why is the tails array always strictly increasing?
Chopping a longer chain gives a shorter chain with a smaller tail, and tails[k] is the smallest such tail, so values must increase with length.
For each new x in patience sorting, what do you do?
lower_bound for first tails[k] >= x; replace it, or append x if x exceeds all tails.
Why use lower_bound (>=) instead of upper_bound (>) for strict LIS?
To avoid equal values forming a fake longer increasing chain; >= keeps it strictly increasing.
Does len(tails) equal the LIS length? Is tails the actual LIS?
len(tails) = correct LIS length; but tails itself is NOT a valid subsequence (need predecessor pointers to recover it).
What are the time complexities of the two LIS methods?
O(n²) DP, and O(n log n) with binary search over tails.
Recall Feynman: explain to a 12-year-old
Imagine stacking cards face-up in piles, left to right. Rule: a card can go on a pile only if it's bigger than that pile's top card, and you always put it on the leftmost pile where it fits — if it fits nowhere, start a brand-new pile to the right. The number of piles you end up with is the length of the longest "always-getting-bigger" line of cards you could pick! Each pile's top is kept as small as possible so more cards can stack on later. That "leftmost pile" choice is just the binary search.
Dekho, LIS ka matlab hai: array me se kuch elements delete karke (order badle bina) ek aisi sequence banao jo strictly badhti jaye, aur uski sabse lambi length chahiye. Yaad rakho — subsequence me gaps allowed hain, subarray me nahi. Brute force me 2^n subsequences hote hain, isliye smart approach chahiye.
Pehla tareeka O(n^2) DP hai. Idea simple: dp[i] rakho = "index i pe khatam hone wali longest increasing subsequence ki length". Har i ke liye peeche dekho — jitne bhi j aise hain jahan A[j] < A[i], unme se best dp[j] uthao aur +1 kar do. Final answer = sabhi dp[i] ka max, kyunki LIS kahin bhi end ho sakti hai.
Doosra tareeka O(n log n) — yeh patience sorting wala jugaad hai. Ek tails array rakho jisme tails[k] = "length k+1 wali increasing subsequence ka sabse chhota possible last value". Har naye x ke liye binary search se pehla tails[k] >= x dhoondo: mil gaya to wahan x rakh do (tail chhota karke future me extend karna easy banaya), nahi mila to x ko append kar do (ek lambi chain ban gayi). Akhir me len(tails) hi LIS length hai. Important warning:tails khud asli subsequence NAHI hai — values overwrite hoti rehti hain — sirf uski length sahi hai. Strict LIS ke liye lower_bound (>=) use karo, taaki barabar values fake chain na bana de.