Skip to content

Commit 14108df

Browse files
refactor 300
1 parent f5afb98 commit 14108df

File tree

2 files changed

+125
-22
lines changed

2 files changed

+125
-22
lines changed

src/main/java/com/fishercoder/solutions/_300.java

+99-22
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,115 @@
44

55
public class _300 {
66

7+
/**
8+
* credit: https://leetcode.com/problems/longest-increasing-subsequence/solution/
9+
*/
710
public static class Solution1 {
11+
/**
12+
* brute force:
13+
* Time: O(2^n), size of recursion tree will be: 2^n
14+
* Space: O(n^2)
15+
* will result in Time Limit Exceeded exception.
16+
* <p>
17+
* The idea is straightforward: we'll iterate through each number, check to see if its next neighbor is smaller or bigger than itself,
18+
* if bigger, then we'll take it, if not, we'll not take it.
19+
*/
20+
public int lengthOfLIS(int[] nums) {
21+
return recursion(nums, Integer.MIN_VALUE, 0);
22+
}
23+
24+
private int recursion(int[] nums, int prev, int curr) {
25+
if (curr == nums.length) {
26+
return 0;
27+
}
28+
int taken = 0;
29+
if (nums[curr] > prev) {
30+
taken = 1 + recursion(nums, nums[curr], curr + 1);
31+
}
32+
int notTaken = recursion(nums, prev, curr + 1);
33+
return Math.max(taken, notTaken);
34+
}
35+
}
36+
37+
public static class Solution2 {
38+
/**
39+
* This is an iteration on the previous solution, we use a 2-d array to memoize the previously calculated result
40+
* Time: O(n^2)
41+
* Space: O(n^2)
42+
*/
43+
public int lengthOfLIS(int[] nums) {
44+
int len = nums.length;
45+
int[][] memo = new int[len + 1][len];
46+
for (int[] m : memo) {
47+
Arrays.fill(m, -1);
48+
}
49+
return recusionWithMemo(nums, -1, 0, memo);
50+
}
51+
52+
private int recusionWithMemo(int[] nums, int prevIndex, int currIndex, int[][] memo) {
53+
if (currIndex == nums.length) {
54+
return 0;
55+
}
56+
if (memo[prevIndex + 1][currIndex] >= 0) {
57+
//because we initialize all elements in memo to be -1,
58+
// so if it's not -1, then it means we have computed this value before,
59+
// we'll just return it and this way it avoid duplicate recursion
60+
return memo[prevIndex + 1][currIndex];
61+
}
62+
int taken = 0;
63+
if (prevIndex < 0 || nums[currIndex] > nums[prevIndex]) {
64+
taken = 1 + recusionWithMemo(nums, currIndex, currIndex + 1, memo);
65+
}
66+
int notTaken = recusionWithMemo(nums, prevIndex, currIndex + 1, memo);
67+
memo[prevIndex + 1][currIndex] = Math.max(taken, notTaken);
68+
return memo[prevIndex + 1][currIndex];
69+
}
70+
}
71+
72+
public static class Solution3 {
73+
/**
74+
* DP solution
75+
* Time: O(n^2)
76+
* Space: O(n)
77+
*/
78+
public int lengthOfLIS(int[] nums) {
79+
if (nums.length == 0) {
80+
return 0;
81+
}
82+
int[] dp = new int[nums.length];
83+
dp[0] = 1;
84+
int result = 1;
85+
for (int i = 1; i < nums.length; i++) {
86+
int maxVal = 0;
87+
for (int j = 0; j < i; j++) {
88+
if (nums[i] > nums[j]) {
89+
maxVal = Math.max(maxVal, dp[j]);
90+
}
91+
}
92+
dp[i] = maxVal + 1;
93+
result = Math.max(result, dp[i]);
94+
}
95+
return result;
96+
}
97+
}
898

99+
public static class Solution4 {
9100
/**
10-
* credit: https://discuss.leetcode.com/topic/28719/short-java-solution-using-dp-o-n-log-n
11-
* The idea is that as you iterate the sequence,
12-
* you keep track of the minimum value a subsequence of given length might end with,
13-
* for all so far possible subsequence lengths.
14-
* So dp[i] is the minimum value a subsequence of length i+1 might end with.
15-
* Having this info, for each new number we iterate to,
16-
* we can determine the longest subsequence where it can be appended using binary search.
17-
* The final answer is the length of the longest subsequence we found so far.
101+
* use binary search.
102+
* Time: O(nlogn)
103+
* Space: O(n)
104+
* <p>
105+
* The reason we can use binary search here is because all numbers we put into dp array are sorted
18106
*/
19107
public int lengthOfLIS(int[] nums) {
20108
int[] dp = new int[nums.length];
21109
int len = 0;
22-
for (int x : nums) {
23-
/**Java Doc of this binarySearch API:
24-
* @return index of the search key, if it is contained in the array
25-
* within the specified range;
26-
* otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
27-
* <i>insertion point</i> is defined as the point at which the
28-
* key would be inserted into the array: the index of the first
29-
* element in the range greater than the key,
30-
* or <tt>toIndex</tt> if all
31-
* elements in the range are less than the specified key. Note
32-
* that this guarantees that the return value will be &gt;= 0 if
33-
* and only if the key is found.*/
34-
int index = Arrays.binarySearch(dp, 0, len, x);
110+
for (int num : nums) {
111+
int index = Arrays.binarySearch(dp, 0, len, num);
35112
if (index < 0) {
36113
index = -(index + 1);
37114
}
38-
dp[index] = x;
115+
dp[index] = num;
39116
if (index == len) {
40117
len++;
41118
}

src/test/java/com/fishercoder/_300Test.java

+26
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,44 @@
99
public class _300Test {
1010

1111
private static _300.Solution1 solution1;
12+
private static _300.Solution2 solution2;
13+
private static _300.Solution3 solution3;
14+
private static _300.Solution4 solution4;
1215
private static int[] nums;
1316

1417
@BeforeClass
1518
public static void setup() {
1619
solution1 = new _300.Solution1();
20+
solution2 = new _300.Solution2();
21+
solution3 = new _300.Solution3();
22+
solution4 = new _300.Solution4();
1723
}
1824

1925
@Test
2026
public void test1() {
2127
nums = new int[]{10, 9, 2, 5, 3, 7, 101, 18};
2228
assertEquals(4, solution1.lengthOfLIS(nums));
29+
assertEquals(4, solution2.lengthOfLIS(nums));
30+
assertEquals(4, solution3.lengthOfLIS(nums));
31+
assertEquals(4, solution4.lengthOfLIS(nums));
32+
}
33+
34+
@Test
35+
public void test2() {
36+
nums = new int[]{0, 1, 0, 3, 2, 3};
37+
assertEquals(4, solution1.lengthOfLIS(nums));
38+
assertEquals(4, solution2.lengthOfLIS(nums));
39+
assertEquals(4, solution3.lengthOfLIS(nums));
40+
assertEquals(4, solution4.lengthOfLIS(nums));
41+
}
2342

43+
@Test
44+
public void test3() {
45+
nums = new int[]{7, 7, 7, 7, 7, 7, 7};
46+
assertEquals(1, solution1.lengthOfLIS(nums));
47+
assertEquals(1, solution2.lengthOfLIS(nums));
48+
assertEquals(1, solution3.lengthOfLIS(nums));
49+
assertEquals(1, solution3.lengthOfLIS(nums));
2450
}
2551

2652
}

0 commit comments

Comments
 (0)