Longest Increasing Subsequence in DSA Typescript - Time & Space Complexity
We want to understand how the time needed to find the longest increasing subsequence changes as the input list grows.
How does the number of steps increase when the list gets longer?
Analyze the time complexity of the following code snippet.
function lengthOfLIS(nums: number[]): number {
const n = nums.length;
const dp = new Array(n).fill(1);
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
return Math.max(...dp);
}
This code finds the length of the longest increasing subsequence by checking all pairs of elements.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops comparing pairs of elements.
- How many times: Outer loop runs n times; inner loop runs up to i times, so roughly n x n = n² times.
As the list size grows, the number of comparisons grows much faster because each new element is compared with all before it.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 100 comparisons |
| 100 | About 10,000 comparisons |
| 1000 | About 1,000,000 comparisons |
Pattern observation: Operations grow roughly with the square of the input size.
Time Complexity: O(n²)
This means if the input list doubles in size, the work needed grows about four times.
[X] Wrong: "The algorithm only looks at each element once, so it must be O(n)."
[OK] Correct: Each element is compared with many others inside nested loops, so the total steps add up much more than just once per element.
Understanding this time complexity helps you explain how your solution scales and shows you can analyze nested loops clearly, a key skill in interviews.
"What if we used a binary search approach inside the loop to improve the search? How would the time complexity change?"
Practice
Solution
Step 1: Understand the LIS definition
The Longest Increasing Subsequence is a subsequence where every next number is strictly greater than the previous one.Step 2: Compare options with definition
The longest subsequence where each number is larger than the previous one matches this definition exactly, others describe different or incorrect sequences.Final Answer:
The longest subsequence where each number is larger than the previous one -> Option AQuick Check:
LIS means strictly increasing subsequence [OK]
- Confusing increasing with decreasing subsequence
- Thinking LIS means contiguous sequence
- Assuming equal numbers count as increasing
Solution
Step 1: Check parameter type
The input should be an array of numbers, so type must be number[].Step 2: Check return type
The function returns the length of LIS, which is a number.Final Answer:
function lengthOfLIS(nums: number[]): number -> Option CQuick Check:
Input array of numbers, output number length [OK]
- Using string type for input instead of number array
- Returning string instead of number
- Using void return type when output is needed
function lengthOfLIS(nums: number[]): number {
const dp = new Array(nums.length).fill(1);
for (let i = 1; i < nums.length; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
return Math.max(...dp);
}
console.log(lengthOfLIS([10, 9, 2, 5, 3, 7, 101, 18]));Solution
Step 1: Understand the DP array construction
dp[i] stores length of LIS ending at index i. Initialize all to 1.Step 2: Trace dp updates for input
For input [10,9,2,5,3,7,101,18], dp becomes [1,1,1,2,2,3,4,4]. Max is 4.Step 3: Re-check the dp array
Actually, dp updates to [1,1,1,2,2,3,5,5] because 101 extends the subsequence ending at 7 (length 4), and 18 extends subsequence ending at 7 (length 4) as well.Final Answer:
5 -> Option AQuick Check:
LIS length for given array is 5 [OK]
- Confusing LIS length with subsequence elements count
- Forgetting to update dp[i] with max value
- Misreading nested loops indices
function lengthOfLIS(nums: number[]): number {
const dp = new Array(nums.length).fill(0);
for (let i = 1; i < nums.length; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
return Math.max(...dp);
}Solution
Step 1: Check dp initialization
dp should start with 1 because each element alone is an LIS of length 1.Step 2: Understand impact of zero initialization
Starting with 0 causes dp values to be underestimated, leading to wrong max LIS length.Final Answer:
Initialize dp array with 1 instead of 0 -> Option BQuick Check:
dp starts at 1 for correct LIS length [OK]
- Initializing dp with 0 causing wrong results
- Changing loop start incorrectly
- Returning min instead of max
[3, 10, 2, 1, 20], what is the length of the Longest Increasing Subsequence if you must also return the subsequence itself? Which subsequence is correct?Solution
Step 1: Find LIS length and subsequence
Possible LIS are [3,10,20] and [1,20], length 3 and 2 respectively. The longest is length 3.Step 2: Verify subsequence correctness
[3,10,20] is strictly increasing and length 3, matching the longest LIS length.Final Answer:
Length: 3, Subsequence: [3, 10, 20] -> Option DQuick Check:
LIS length 3 with subsequence [3,10,20] [OK]
- Choosing subsequence with wrong order
- Confusing length with subsequence elements
- Assuming non-strictly increasing sequences
Ready to prove it?
Pass the test and this pattern moves unknown
