Skip to content

Commit 153e3e1

Browse files
committed
Add LongestIncreasingSubsequenceNLogN class and corresponding test class
1 parent 9186af6 commit 153e3e1

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,71 @@
11
package com.thealgorithms.dynamicprogramming;
22

3+
/**
4+
* Implementation of the Longest Increasing Subsequence (LIS) problem using
5+
* an O(n log n) dynamic programming solution enhanced with binary search.
6+
*
7+
* @author Vusal Huseynov (https://github.com/huseynovvusal)
8+
*/
39
public class LongestIncreasingSubsequenceNLogN {
10+
11+
/**
12+
* Finds the index of the smallest element in the array that is greater than
13+
* or equal to the target using binary search. If no such element exists,
14+
* returns the index where the target can be inserted to maintain sorted order.
15+
*
16+
* @param arr The array to search in (assumed to be sorted up to a certain point).
17+
* @param target The target value to find the lower bound for.
18+
* @return The index of the lower bound.
19+
*/
20+
private static int lowerBound(int[] arr, int target) {
21+
int l = 0, r = arr.length;
22+
23+
while (l < r) {
24+
int mid = l + (r - l) / 2;
25+
26+
if (target > arr[mid]) {
27+
// Move right if target is greater than mid element
28+
l = mid + 1;
29+
} else {
30+
// Move left if target is less than or equal to mid element
31+
r = mid;
32+
}
33+
}
34+
35+
// Return the index where the target can be inserted
36+
return l;
37+
}
38+
39+
/**
40+
* Calculates the length of the Longest Increasing Subsequence (LIS) in the given array.
41+
*
42+
* @param arr The input array of integers.
43+
* @return The length of the LIS.
44+
*/
45+
public static int lengthOfLIS(int[] arr) {
46+
if (arr == null || arr.length == 0) {
47+
return 0; // Return 0 for empty or null arrays
48+
}
49+
50+
// tails[i] - the smallest end element of an increasing subsequence of length i+1
51+
int[] tails = new int[arr.length];
52+
// size - the length of the longest increasing subsequence found so far
53+
int size = 0;
54+
55+
for (int x : arr) {
56+
// Find the position to replace or extend the subsequence
57+
int index = lowerBound(tails, x);
58+
59+
// Update the tails array with the current element
60+
tails[index] = x;
61+
62+
// If the element extends the subsequence, increase the size
63+
if (index == size) {
64+
size++;
65+
}
66+
}
67+
68+
// Return the length of the LIS
69+
return size;
70+
}
471
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,30 @@
11
package com.thealgorithms.dynamicprogramming;
22

3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.stream.Stream;
6+
import org.junit.jupiter.params.ParameterizedTest;
7+
import org.junit.jupiter.params.provider.Arguments;
8+
import org.junit.jupiter.params.provider.MethodSource;
9+
310
public class LongestIncreasingSubsequenceNLogNTest {
4-
}
11+
12+
private static Stream<Arguments> provideTestCases() {
13+
return Stream.of(
14+
Arguments.of(new int[] {10, 9, 2, 5, 3, 7, 101, 18}, 4),
15+
Arguments.of(new int[] {0, 1, 0, 3, 2, 3}, 4),
16+
Arguments.of(new int[] {7, 7, 7, 7, 7}, 1),
17+
Arguments.of(new int[] {1, 3, 5, 4, 7}, 4),
18+
Arguments.of(new int[] {}, 0),
19+
Arguments.of(new int[] {10}, 1),
20+
Arguments.of(new int[] {3, 10, 2, 1, 20}, 3),
21+
Arguments.of(new int[] {50, 3, 10, 7, 40, 80}, 4)
22+
);
23+
}
24+
25+
@ParameterizedTest
26+
@MethodSource("provideTestCases")
27+
public void testLengthOfLIS(int[] input, int expected) {
28+
assertEquals(expected, LongestIncreasingSubsequenceNLogN.lengthOfLIS(input));
29+
}
30+
}

0 commit comments

Comments
 (0)