Print Longest Increasing Subsequence
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ nums.length ≤ 12 - ◆
-1000 ≤ nums[i] ≤ 1000 - ◆
If more than one longest increasing subsequence exists, return the one that ends at the earliest-finishing chain — built by always preferring the smallest-index predecessor whenever two predecessors would extend a chain to the same length
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Recursive Backtrack After Building the DP Table
OptimalFirst fill a length-only dp[i] table exactly like the length-only version of this problem: dp[i] holds the length of the longest increasing subsequence ending at index i, found by checking every earlier index j and extending dp[j] whenever nums[j] is smaller. A parent[i] array is filled alongside it, recording which earlier index produced dp[i]'s best value — only updating on a strict improvement, so the first predecessor to reach a given length is the one kept. Once every index is filled, the index holding the largest dp value marks where the answer ends. A small recursive helper then walks parent pointers back to the start, and — because it appends the current index's value only after recursing on its parent — the values land in the result in correct left-to-right order automatically.
O(n²)O(n)1class Solution {
2 public int[] printLIS(int[] nums) {
3 int n = nums.length;
4 int[] dp = new int[n];
5 Arrays.fill(dp, 1);
6 int[] parent = new int[n];
7 Arrays.fill(parent, -1);
8 for (int i = 1; i < n; i++) {
9 for (int j = 0; j < i; j++) {
10 if (nums[j] < nums[i] && dp[j] + 1 > dp[i]) {
11 dp[i] = dp[j] + 1;
12 parent[i] = j;
13 }
14 }
15 }
16 int maxIdx = 0;
17 for (int i = 1; i < n; i++) {
18 if (dp[i] > dp[maxIdx]) maxIdx = i;
19 }
20 List<Integer> result = new ArrayList<>();
21 backtrack(nums, parent, maxIdx, result);
22 int[] out = new int[result.size()];
23 for (int k = 0; k < out.length; k++) out[k] = result.get(k);
24 return out;
25 }
26
27 private void backtrack(int[] nums, int[] parent, int i, List<Integer> result) {
28 if (i == -1) return;
29 backtrack(nums, parent, parent[i], result);
30 result.add(nums[i]);
31 }
32}Iterative Backtrack After Building the DP Table
ApproachBuild the exact same dp[]/parent[] tables as the recursive version. Since dp[maxIdx] already says how long the final answer is, a result array of that exact size can be allocated up front and filled from its last slot backward: starting at maxIdx, place its value in the last slot, step to parent[maxIdx], place that value one slot earlier, and keep following parent pointers until one points to nothing (-1). Filling from the back removes the need for any separate reversal step at the end.
O(n²)O(n)1class Solution {
2 public int[] printLIS(int[] nums) {
3 int n = nums.length;
4 int[] dp = new int[n];
5 Arrays.fill(dp, 1);
6 int[] parent = new int[n];
7 Arrays.fill(parent, -1);
8 for (int i = 1; i < n; i++) {
9 for (int j = 0; j < i; j++) {
10 if (nums[j] < nums[i] && dp[j] + 1 > dp[i]) {
11 dp[i] = dp[j] + 1;
12 parent[i] = j;
13 }
14 }
15 }
16 int maxIdx = 0;
17 for (int i = 1; i < n; i++) {
18 if (dp[i] > dp[maxIdx]) maxIdx = i;
19 }
20 int[] result = new int[dp[maxIdx]];
21 int pos = dp[maxIdx] - 1;
22 int cur = maxIdx;
23 while (cur != -1) {
24 result[pos--] = nums[cur];
25 cur = parent[cur];
26 }
27 return result;
28 }
29}