mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-07 17:56:02 +08:00
Add LongestIncreasingSubsequenceNLogN (#6221)
This commit is contained in:
@ -0,0 +1,75 @@
|
|||||||
|
package com.thealgorithms.dynamicprogramming;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the Longest Increasing Subsequence (LIS) problem using
|
||||||
|
* an O(n log n) dynamic programming solution enhanced with binary search.
|
||||||
|
*
|
||||||
|
* @author Vusal Huseynov (https://github.com/huseynovvusal)
|
||||||
|
*/
|
||||||
|
public final class LongestIncreasingSubsequenceNLogN {
|
||||||
|
private LongestIncreasingSubsequenceNLogN() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the index of the smallest element in the array that is greater than
|
||||||
|
* or equal to the target using binary search. The search is restricted to
|
||||||
|
* the first `size` elements of the array.
|
||||||
|
*
|
||||||
|
* @param arr The array to search in (assumed to be sorted up to `size`).
|
||||||
|
* @param size The number of valid elements in the array.
|
||||||
|
* @param target The target value to find the lower bound for.
|
||||||
|
* @return The index of the lower bound.
|
||||||
|
*/
|
||||||
|
private static int lowerBound(int[] arr, int target, int size) {
|
||||||
|
int l = 0;
|
||||||
|
int r = size;
|
||||||
|
|
||||||
|
while (l < r) {
|
||||||
|
int mid = l + (r - l) / 2;
|
||||||
|
|
||||||
|
if (target > arr[mid]) {
|
||||||
|
// Move right if target is greater than mid element
|
||||||
|
l = mid + 1;
|
||||||
|
} else {
|
||||||
|
// Move left if target is less than or equal to mid element
|
||||||
|
r = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the index where the target can be inserted
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the length of the Longest Increasing Subsequence (LIS) in the given array.
|
||||||
|
*
|
||||||
|
* @param arr The input array of integers.
|
||||||
|
* @return The length of the LIS.
|
||||||
|
*/
|
||||||
|
public static int lengthOfLIS(int[] arr) {
|
||||||
|
if (arr == null || arr.length == 0) {
|
||||||
|
return 0; // Return 0 for empty or null arrays
|
||||||
|
}
|
||||||
|
|
||||||
|
// tails[i] - the smallest end element of an increasing subsequence of length i+1
|
||||||
|
int[] tails = new int[arr.length];
|
||||||
|
// size - the length of the longest increasing subsequence found so far
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
for (int x : arr) {
|
||||||
|
// Find the position to replace or extend the subsequence
|
||||||
|
int index = lowerBound(tails, x, size);
|
||||||
|
|
||||||
|
// Update the tails array with the current element
|
||||||
|
tails[index] = x;
|
||||||
|
|
||||||
|
// If the element extends the subsequence, increase the size
|
||||||
|
if (index == size) {
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the length of the LIS
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.thealgorithms.dynamicprogramming;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
public class LongestIncreasingSubsequenceNLogNTest {
|
||||||
|
|
||||||
|
private static Stream<Arguments> provideTestCases() {
|
||||||
|
return Stream.of(Arguments.of(new int[] {10, 9, 2, 5, 3, 7, 101, 18}, 4), Arguments.of(new int[] {0, 1, 0, 3, 2, 3}, 4), Arguments.of(new int[] {7, 7, 7, 7, 7}, 1), Arguments.of(new int[] {1, 3, 5, 4, 7}, 4), Arguments.of(new int[] {}, 0), Arguments.of(new int[] {10}, 1),
|
||||||
|
Arguments.of(new int[] {3, 10, 2, 1, 20}, 3), Arguments.of(new int[] {50, 3, 10, 7, 40, 80}, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideTestCases")
|
||||||
|
public void testLengthOfLIS(int[] input, int expected) {
|
||||||
|
assertEquals(expected, LongestIncreasingSubsequenceNLogN.lengthOfLIS(input));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user