Longest Increasing Subsequence in DSA C++ - Time & Space Complexity
We want to understand how the time needed to find the longest increasing subsequence grows as the input list gets bigger.
How does the number of steps change when the input size increases?
Analyze the time complexity of the following code snippet.
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1);
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
This code finds the length of the longest increasing subsequence by checking all pairs and building up solutions.
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 input size grows, the number of comparisons grows much faster because each new element is compared with all previous ones.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 100 comparisons |
| 100 | About 10,000 comparisons |
| 1000 | About 1,000,000 comparisons |
Pattern observation: The operations grow roughly by the square of the input size.
Time Complexity: O(n²)
This means if the input doubles, the time to run roughly quadruples because every element is compared with many others.
[X] Wrong: "The algorithm runs in linear time because it just loops through the list once."
[OK] Correct: There are actually two loops nested inside each other, so the inner loop runs many times for each outer loop step, making it much slower than just one pass.
Understanding this time complexity helps you explain why some solutions are slower and shows you the value of more efficient methods, which is a great skill to share in interviews.
"What if we used a binary search approach inside the loop to find positions? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem definition
The LIS problem looks for a subsequence where every next number is bigger than the one before it.Step 2: Compare options with the definition
The longest subsequence where each number is larger than the previous one matches the definition exactly, others describe different or incorrect sequences.Final Answer:
The longest subsequence where each number is larger than the previous one -> Option BQuick Check:
LIS means increasing subsequence = The longest subsequence where each number is larger than the previous one [OK]
- Confusing increasing with decreasing subsequence
- Thinking LIS means contiguous subarray
- Assuming equal numbers count as increasing
Solution
Step 1: Check correct vector declaration syntax
In C++, std::vector<int> lis(n, 1); creates a vector of size n with all values initialized to 1.Step 2: Validate each option
std::vector<int> lis(n, 1); uses correct syntax and initialization. vector<int> lis(n); misses initialization, C misses template argument, D has wrong template syntax.Final Answer:
std::vector<int> lis(n, 1); -> Option AQuick Check:
Correct vector syntax with initialization = std::vector<int> lis(n, 1); [OK]
- Omitting std:: or using wrong template syntax
- Not initializing vector values
- Using wrong brackets or missing template argument
std::vector<int> arr = {10, 22, 9, 33, 21, 50, 41, 60};
int n = arr.size();
std::vector<int> lis(n, 1);
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (arr[i] > arr[j] && lis[i] < lis[j] + 1) {
lis[i] = lis[j] + 1;
}
}
}
int max_lis = 0;
for (int i = 0; i < n; i++) {
if (lis[i] > max_lis) max_lis = lis[i];
}
std::cout << max_lis << std::endl;Solution
Step 1: Trace LIS calculation for each element
Calculate lis array step-by-step: lis = [1,2,1,3,2,4,4,5]Step 2: Find maximum value in lis array
Maximum lis value is 5, which is printed as output.Final Answer:
5 -> Option DQuick Check:
Max LIS length = 5 [OK]
- Confusing subsequence with subarray
- Not updating lis[i] correctly
- Forgetting to find max after loops
std::vector<int> arr = {3, 10, 2, 1, 20};
int n = arr.size();
std::vector<int> lis(n, 1);
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (arr[i] > arr[j]) {
lis[i] = lis[j] + 1;
}
}
}
int max_lis = *max_element(lis.begin(), lis.end());
std::cout << max_lis << std::endl;Solution
Step 1: Analyze update condition inside nested loops
The code updates lis[i] without checking if lis[j] + 1 is greater, causing wrong LIS values.Step 2: Identify missing condition
Adding 'if (lis[i] < lis[j] + 1)' before update fixes the bug.Final Answer:
Missing check if lis[i] < lis[j] + 1 before updating -> Option AQuick Check:
Update only if new LIS is longer [OK]
- Updating lis[i] blindly overwrites correct values
- Confusing loop indices
- Incorrect use of max_element function
{5, 7, 4, 8, 6, 9}, what is the length of the Longest Increasing Subsequence if you must also ensure the subsequence elements are at even indices only (0-based)?Solution
Step 1: Identify even indices (0-based)
Positions 0, 2, 4 have values 5, 4, 6.Step 2: Compute LIS on {5, 4, 6}
Possible increasing subsequences: {5, 6} or {4, 6}, both length 2. No length 3 possible (5 > 4).Final Answer:
2 -> Option CQuick Check:
LIS length on even indices only = 2 [OK]
- Ignoring index restriction
- Using full sequence instead of filtered
- Assuming contiguous subsequence
Ready to prove it?
Pass the test and this pattern moves unknown
