Commit 9bd1a7dc authored by Fokion Zervoudakis's avatar Fokion Zervoudakis

Add DP LIS.

parent 9cf40a74
package misc;
import search.BinSearch;
class DpLis {
/**
Asymptotic analysis:
<ul>
<li>time_worst=O(n log n)
<li>space_worst=O(n)
</ul>
@param A an array of integers
@return the length of the longest increasing sub-sequence in {@code A}
*/
int len(int[] A) {
int[] B = new int[A.length];
int len = 0;
for (int n : A) {
int i = BinSearch.it(B, 0, len - 1, n);
if (i < 0) {
i = -(i + 1);
}
B[i] = n;
if (i == len) {
len++;
}
}
return len;
}
}
......@@ -5,7 +5,7 @@ import annotation.Bit;
/**
{@link java.util.Arrays#binarySearch(int[], int)}
*/
class BinSearch {
public class BinSearch {
/**
Searches the specified array for the specified element using the binary
search algorithm.
......@@ -26,9 +26,12 @@ class BinSearch {
@return the index of {@code n} in {@code A}, if {@code n} is in {@code A},
else <code>(-(<i>insertion point</i>) - 1)</code>
*/
@Bit
int it(int[] A, int n) {
int l = 0, r = A.length - 1;
return it(A, 0, A.length - 1, n);
}
@Bit
public static int it(int[] A, int l, int r, int n) {
while (r >= l) {
int m = (l + r) >>> 1;
if (A[m] < n) {
......@@ -39,7 +42,7 @@ class BinSearch {
return m;
}
}
return -l;
return -(l + 1);
}
/**
......@@ -61,19 +64,19 @@ class BinSearch {
else <code>(-(<i>insertion point</i>) - 1)</code>
*/
int rec(int[] A, int n) {
return rec(A, n, 0, A.length - 1);
return rec(A, 0, A.length - 1, n);
}
@Bit
private int rec(int[] A, int n, int l, int r) {
private int rec(int[] A, int l, int r, int n) {
if (l > r) {
return -l;
return -(l + 1);
}
int m = (l + r) >>> 1;
if (A[m] < n) {
return rec(A, n, m + 1, r);
return rec(A, m + 1, r, n);
} else if (A[m] > n) {
return rec(A, n, l, m - 1);
return rec(A, l, m - 1, n);
} else {
return m;
}
......
package misc;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class DpLisTest {
private DpLis lis;
@BeforeEach
void beforeEach() {
lis = new DpLis();
}
@Test
void itReturnsTheLisOfZeroElements() {
assertEquals(0, lis.len(new int[0]));
}
@Test
void itReturnsTheLisOfOneElement() {
assertEquals(1, lis.len(new int[] { 1 }));
}
@Test
void itReturnsTheLisOfManyAscendingElements() {
assertEquals(3, lis.len(new int[] { 1, 2, 3 }));
}
@Test
void itReturnsTheLisOfManyDescendingElements() {
assertEquals(1, lis.len(new int[] { 3, 2, 1 }));
}
@Test
void itReturnsTheLisOfManyUnorderedElements() {
// The first 16 terms of the binary van der Corput sequence:
var A = new int[] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
assertEquals(6, lis.len(A));
}
}
......@@ -4,6 +4,8 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertEquals;
class BinSearchTest {
......@@ -16,14 +18,23 @@ class BinSearchTest {
@Nested
class WhenItHasZeroElements {
private int[] A;
@BeforeEach
void beforeEach() {
A = new int[0];
}
@Test
void itReturnsTheInsertionPointIteratively() {
assertEquals(0, search.it(new int[0], 1));
assertEquals(-1, Arrays.binarySearch(A, 1));
assertEquals(-1, search.it(A, 1));
}
@Test
void itReturnsTheInsertionPointRecursively() {
assertEquals(0, search.rec(new int[0], 1));
assertEquals(-1, Arrays.binarySearch(A, 1));
assertEquals(-1, search.rec(A, 1));
}
}
......@@ -38,38 +49,44 @@ class BinSearchTest {
@Test
void itReturnsTheIndexOfAnElementIfItExists() {
assertEquals(1, Arrays.binarySearch(A, 8));
assertEquals(1, search.it(A, 8));
assertEquals(1, search.rec(A, 8));
}
@Test
void itReturnsTheIndexOfTheFirstElement() {
assertEquals(0, Arrays.binarySearch(A, 7));
assertEquals(0, search.it(A, 7));
assertEquals(0, search.rec(A, 7));
}
@Test
void itReturnsTheIndexOfTheLastElement() {
assertEquals(3, Arrays.binarySearch(A, 11));
assertEquals(3, search.it(A, 11));
assertEquals(3, search.rec(A, 11));
}
@Test
void itReturnsTheLeftmostInsertionPointIfTheElementDoesNotExist() {
assertEquals(0, search.it(A, 6));
assertEquals(0, search.rec(A, 6));
assertEquals(-1, Arrays.binarySearch(A, 6));
assertEquals(-1, search.it(A, 6));
assertEquals(-1, search.rec(A, 6));
}
@Test
void itReturnsANegativeInsertionPointIfTheElementDoesNotExist() {
assertEquals(-3, search.it(A, 10));
assertEquals(-3, search.rec(A, 10));
assertEquals(-4, Arrays.binarySearch(A, 10));
assertEquals(-4, search.it(A, 10));
assertEquals(-4, search.rec(A, 10));
}
@Test
void itReturnsARightmostNegativeInsertionPointIfTheElementDoesNotExist() {
assertEquals(-4, search.it(A, 12));
assertEquals(-4, search.rec(A, 12));
assertEquals(-5, Arrays.binarySearch(A, 12));
assertEquals(-5, search.it(A, 12));
assertEquals(-5, search.rec(A, 12));
}
}
......@@ -102,20 +119,20 @@ class BinSearchTest {
@Test
void itReturnsTheLeftmostInsertionPointIfTheElementDoesNotExist() {
assertEquals(0, search.it(A, 6));
assertEquals(0, search.rec(A, 6));
assertEquals(-1, search.it(A, 6));
assertEquals(-1, search.rec(A, 6));
}
@Test
void itReturnsANegativeInsertionPointIfTheElementDoesNotExist() {
assertEquals(-2, search.it(A, 10));
assertEquals(-2, search.rec(A, 10));
assertEquals(-3, search.it(A, 10));
assertEquals(-3, search.rec(A, 10));
}
@Test
void itReturnsARightmostNegativeInsertionPointIfTheElementDoesNotExist() {
assertEquals(-3, search.it(A, 12));
assertEquals(-3, search.rec(A, 12));
assertEquals(-4, search.it(A, 12));
assertEquals(-4, search.rec(A, 12));
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment