Longest Increasing Subsequence in DSA Java - 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 grow when the list gets bigger?
Analyze the time complexity of the following code snippet.
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp, 1);
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
int max = 1;
for (int length : dp) max = Math.max(max, length);
return max;
}
This code finds the length of the longest increasing subsequence in an array using dynamic programming.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops comparing pairs of elements to update subsequence lengths.
- 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 elements.
| 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, so doubling the input makes the work about four times bigger.
Time Complexity: O(n²)
This means the time needed grows roughly with the square of the number of elements in the input list.
[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 grow much faster than just once per element.
Understanding this time complexity helps you explain why some solutions are slower and shows your skill in analyzing nested loops, a common interview topic.
"What if we used a binary search approach to build the subsequence? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem definition
The Longest Increasing Subsequence is a subsequence where every next number is strictly greater than the previous one.Step 2: Compare options with the definition
The longest subsequence where each number is larger than the previous one matches the definition exactly, while others describe different patterns.Final Answer:
The longest subsequence where each number is larger than the previous one -> Option DQuick Check:
LIS = strictly increasing subsequence [OK]
- Confusing subsequence with substring
- Thinking LIS means non-decreasing instead of strictly increasing
- Mixing up increasing with decreasing sequences
arr of size n?Solution
Step 1: Understand LIS initialization
Each element starts with LIS length 1 because the smallest subsequence is the element itself.Step 2: Check code correctness
int[] lis = new int[n]; for(int i=0; ifill on array. int lis[] = new int[n]; Arrays.fill(lis, 0); fills with 0, incorrect for LIS.Final Answer:
int[] lis = new int[n]; for(int i=0; i -> Option CQuick Check:
Initialize LIS array with 1s [OK]
- Initializing LIS array with zeros
- Using non-existent array methods like fill()
- Not initializing LIS array before DP
arr = {10, 22, 9, 33, 21, 50, 41, 60}?
int[] arr = {10, 22, 9, 33, 21, 50, 41, 60};
int n = arr.length;
int[] lis = new int[n];
for (int i = 0; i < n; i++) lis[i] = 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 = 0;
for (int i = 0; i < n; i++) {
if (lis[i] > max) max = lis[i];
}
System.out.println(max);Solution
Step 1: Calculate LIS array values
For each element, find LIS ending there: - arr[0]=10: lis=1 - arr[1]=22 >10: lis=2 - arr[2]=9: lis=1 - arr[3]=33 >22: lis=3 - arr[4]=21 >10 but <22: lis=2 - arr[5]=50 >33: lis=4 - arr[6]=41 >33 but <50: lis=4 - arr[7]=60 >50: lis=5Step 2: Find max LIS length
Maximum value in lis array is 5.Final Answer:
5 -> Option AQuick Check:
Max LIS length = 5 [OK]
- Confusing subsequence length with subarray length
- Not updating lis[i] correctly inside nested loops
- Forgetting to find max LIS after filling array
arr:
int[] lis = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
lis[i] = 0;
}
for (int i = 1; i < arr.length; 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 = 0;
for (int i = 0; i < lis.length; i++) {
if (lis[i] > max) max = lis[i];
}
System.out.println(max);Solution
Step 1: Check LIS array initialization
LIS array must start with 1 for each element because each element alone forms a subsequence of length 1. Initializing with 0 causes incorrect LIS lengths.Step 2: Verify loops and conditions
Inner loop and comparison are correct. Max initialization to 0 is fine since LIS lengths are positive.Final Answer:
LIS array should be initialized with 1, not 0 -> Option AQuick Check:
Initialize LIS with 1 to avoid zero-length subsequences [OK]
- Initializing LIS array with zeros
- Changing loop ranges incorrectly
- Misunderstanding LIS condition comparison
arr = {3, 10, 2, 1, 20}, which of the following sequences is the Longest Increasing Subsequence (LIS)?Solution
Step 1: Identify increasing subsequences
Check each option for strictly increasing order: - [3, 10, 20]: 3 < 10 < 20 (valid) - [3, 2, 1, 20]: 3 > 2 > 1 (not increasing) - [10, 20]: 10 < 20 (valid but shorter) - [1, 2, 3]: 1 < 2 < 3 (valid but not a subsequence in original order)Step 2: Compare lengths of valid subsequences
[3, 10, 20] length is 3, [10, 20] length is 2, [1, 2, 3] length is 3 but elements not in original order (subsequence must follow original order). [1, 2, 3] is invalid as subsequence because 1 comes after 3 in original array.Final Answer:
[3, 10, 20] -> Option BQuick Check:
LIS must be increasing and follow original order [OK]
- Choosing subsequence not in original order
- Confusing increasing with non-decreasing
- Ignoring subsequence length
Ready to prove it?
Pass the test and this pattern moves unknown
