intermediate8 min read·Updated October 5, 2026
Longest Increasing Subsequence Explained: Tracing [10, 9, 2, 5, 3, 7, 101, 18]
Master the Longest Increasing Subsequence algorithm. Walk through the DP state and binary search approach on [10, 9, 2, 5, 3, 7, 101, 18] step by step.
By Learnisim AI·Published October 5, 2026
LEARNING ARCSetup → Model in the example → Full trace → Twist → Edge cases → Apply
PREREQUISITES
- basic arrays
- introductory dynamic programming
Why
Why Order Matters: The Hidden Subsequence Problem
Phase 1: The Disordered Stream
Imagine you are handed a raw stream of inventory counts, sensor readings, or stock prices:
nums = [10, 9, 2, 5, 3, 7, 101, 18]. You need to find the longest chain of values where each entry is strictly greater than the one before it. But there is a catch: you cannot rearrange the elements. You can only pick numbers out from left to right while preserving their original relative order.At first glance, scanning left to right feels deceptive. We see
10, then 9 (which drops), then 2 (which drops further), before climbing up to 5, 3, 7, 101, and 18. If we just greedily grab the first numbers that look promising, or throw out everything that dips, we lose the larger picture. The sheer number of possible subsets— combinations—means a naive brute-force check will quickly choke as the array grows.Without a structured way to remember what came before, we find ourselves constantly re-evaluating past decisions. We need a concept that lets us track valid increasing paths efficiently without inspecting every exponential combination by hand. That concept is the Longest Increasing Subsequence, and mastering it changes how we handle ordering constraints across computer science.
Model
Building the Dynamic Programming Mental Model for LIS
Phase 2: The DP Table Model
When looking at our working sequence
nums = [10, 9, 2, 5, 3, 7, 101, 18], a brute-force check of every combination fails because there are possible subsequences. Instead, we can model this as a cumulative building process using an array dp, where dp[i] represents the length of the longest increasing subsequence that ends specifically at index .To compute
dp[i], we look backward at all previous indices . If our current number nums[i] is strictly greater than a past number nums[j], it means we can legally append nums[i] to the end of the increasing subsequence that ended at . Thus, the transition rule becomes:Every position starts with a baseline length of 1 (representing the element itself as a subsequence of length one). As we move through the array from left to right, each entry in
dp crystallizes the best historical choice available from its left-hand neighbors.Worked example
Tracing the DP Table and Binary Search for [10, 9, 2, 5, 3, 7, 101, 18]
Phase 3: Walking Through the Lock Sequence
Let us now apply our dynamic programming recurrence and the optimized tails approach to our locked array:
nums = [10, 9, 2, 5, 3, 7, 101, 18]. Our goal is to find the length of the longest strictly increasing subsequence.Given:
nums = [10, 9, 2, 5, 3, 7, 101, 18]Steps (Classic DP Table Trace):
1. Initialize a
2. For each element at index
1. Initialize a
dp array of the same length, where every entry is 1 because any single element is an increasing subsequence of length 1.2. For each element at index
i, check all previous elements j (where j < i). If nums[j] < nums[i], update dp[i] = max(dp[i], dp[j] + 1).Here is how the
dp array evolves step by step across each element:Initial: nums = [10, 9, 2, 5, 3, 7, 101, 18]
dp = [ 1, 1, 1, 1, 1, 1, 1, 1]
dp = [ 1, 1, 1, 1, 1, 1, 1, 1]
i = 0 (10): dp[0] = 1
i = 1 (9): 9 not > 10. dp[1] = 1
i = 2 (2): 2 not > 10, 9. dp[2] = 1
i = 3 (5): 5 > 2 (dp[2]=1). dp[3] = max(1, 1+1) = 2. dp = [1, 1, 1, 2, 1, 1, 1, 1]
i = 4 (3): 3 > 2 (dp[2]=1). dp[4] = max(1, 1+1) = 2. dp = [1, 1, 1, 2, 2, 1, 1, 1]
i = 5 (7): 7 > 2, 5, 3. Max from dp[3] or dp[4] is 2. dp[5] = 2 + 1 = 3.
i = 6(101): 101 > all previous. Max dp is dp[5]=3. dp[6] = 3 + 1 = 4.
i = 7 (18): 18 > 10,9,2,5,3,7. Max dp is dp[5]=3 (from 7). dp[7] = 3 + 1 = 4.
i = 1 (9): 9 not > 10. dp[1] = 1
i = 2 (2): 2 not > 10, 9. dp[2] = 1
i = 3 (5): 5 > 2 (dp[2]=1). dp[3] = max(1, 1+1) = 2. dp = [1, 1, 1, 2, 1, 1, 1, 1]
i = 4 (3): 3 > 2 (dp[2]=1). dp[4] = max(1, 1+1) = 2. dp = [1, 1, 1, 2, 2, 1, 1, 1]
i = 5 (7): 7 > 2, 5, 3. Max from dp[3] or dp[4] is 2. dp[5] = 2 + 1 = 3.
i = 6(101): 101 > all previous. Max dp is dp[5]=3. dp[6] = 3 + 1 = 4.
i = 7 (18): 18 > 10,9,2,5,3,7. Max dp is dp[5]=3 (from 7). dp[7] = 3 + 1 = 4.
Result:
The maximum value in our final
The maximum value in our final
dp table is 4 (found at indices 6 and 7). Thus, the length of the longest increasing subsequence for this sequence is 4.Practice
Predicting the LIS Table State and Output on a Modified Input
Phase 4: Practice Your LIS Tracing Skills
Now it is time to test your mental model against a slight mutation of our working example. Recall our original sequence
nums = [10, 9, 2, 5, 3, 7, 101, 18] which resulted in an LIS length of 4. Let us replace the middle elements to see how the recurrence reacts.Consider the new sequence
nums = [2, 15, 3, 7, 8, 6, 18]. Walk through the dynamic programming table or the tails array approach step by step. For each incoming number, determine whether it extends an existing subsequence or overwrites a tail value.Keep track of the intermediate tails array state as you process each number from left to right. This hands-on trace bridges the gap between passive reading and active algorithmic mastery.
Apply
Transferring the LIS Approach to Non-Array Domains
Phase 5: Applying LIS Beyond Simple Arrays
Now that we have traced our working example
[10, 9, 2, 5, 3, 7, 101, 18] and verified our understanding on edge variations, we can recognize that the core pattern—maintaining smallest possible tails for each subsequence length via binary search—is not restricted to raw numeric arrays. Consider a logistics problem where you receive a stream of rectangular crates, each defined by a width and a height. You want to find the longest sequence of crates that can be nested inside one another, where crate A fits inside crate B strictly if both its width and height are smaller.By sorting the crates primarily by width in ascending order (and handling width ties by sorting heights in descending order), the two-dimensional nesting problem reduces directly to finding the Longest Increasing Subsequence of their heights! The recurrence relation we built for
nums seamlessly translates to this new domain because the sorting eliminates one dimension of uncertainty. Whenever you see a problem asking for a maximal chain of compatible elements where transitivity holds, you are looking at an LIS variant.Whenever structural constraints force data into a partial order, mapping those constraints into an indexable sequence unlocks the exact same efficiency we discovered in our original working example.
FAQ
What is the Longest Increasing Subsequence for [10, 9, 2, 5, 3, 7, 101, 18]?
The length of the LIS is 4. Valid subsequences of length 4 include [2, 3, 7, 101] and [2, 5, 7, 18].
Why can't we just sort the array to find the LIS?
Sorting alters the original relative order of elements. A subsequence must maintain the original left-to-right sequence of elements from the array, just without necessarily being contiguous.
What is the time complexity of the optimized LIS algorithm?
Using dynamic programming with binary search (Patience Sorting approach), the time complexity is O(N log N), compared to the O(N^2) naive DP approach.
What is the difference between a subarray, substring, and subsequence?
A subarray or substring consists of contiguous elements. A subsequence can skip elements, but must maintain their relative order.