Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/main/java/com/thealgorithms/searches/LowerBound.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* This is an extension of BinarySearch.
*
* <p>
* Worst-case performance O(log n) Best-case performance O(1) Average
* Worst-case performance O(log n) Best-case performance O(log n) Average
* performance O(log n) Worst-case space complexity O(1)
*
* @author Pratik Padalia (https://github.com/15pratik)
Expand All @@ -26,10 +26,13 @@ class LowerBound implements SearchAlgorithm {
* @param array is an array where the LowerBound value is to be found
* @param key is an element for which the LowerBound is to be found
* @param <T> is any comparable type
* @return index of the LowerBound element
* @return index of the first element not less than key, or 0 if array is null/empty or key is null
*/
@Override
public <T extends Comparable<T>> int find(T[] array, T key) {
if (array == null || array.length == 0 || key == null) {
return 0;
}
return search(array, key, 0, array.length - 1);
}

Expand All @@ -51,10 +54,8 @@ private <T extends Comparable<T>> int search(T[] array, T key, int left, int rig
int median = (left + right) >>> 1;
int comp = key.compareTo(array[median]);

if (comp == 0) {
return median;
} else if (comp < 0) {
// median position can be a possible solution
if (comp <= 0) {
// key is less than or equal to array[median], median position can be a possible solution
return search(array, key, left, median);
} else {
// key we are looking is greater, so we must look on the right of median position
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/com/thealgorithms/searches/UpperBound.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* This is an extension of BinarySearch.
*
* <p>
* Worst-case performance O(log n) Best-case performance O(1) Average
* Worst-case performance O(log n) Best-case performance O(log n) Average
* performance O(log n) Worst-case space complexity O(1)
*
* @author Pratik Padalia (https://github.com/15pratik)
Expand All @@ -26,10 +26,13 @@ class UpperBound implements SearchAlgorithm {
* @param array is an array where the UpperBound value is to be found
* @param key is an element for which the UpperBound is to be found
* @param <T> is any comparable type
* @return index of the UpperBound element
* @return index of the first element greater than key, last index if no such element exists, or 0 if array is null/empty or key is null
*/
@Override
public <T extends Comparable<T>> int find(T[] array, T key) {
if (array == null || array.length == 0 || key == null) {
return 0;
}
return search(array, key, 0, array.length - 1);
}

Expand Down
27 changes: 27 additions & 0 deletions src/test/java/com/thealgorithms/searches/LowerBoundTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,31 @@ void testLowerBoundNonExistentValue() {
assertEquals(4, lowerBound.find(array, 7), "Lower bound for 7 should be at index 4");
assertEquals(0, lowerBound.find(array, 0), "Lower bound for 0 should be at index 0");
}

/**
* Test finding the lower bound for an element with duplicate occurrences.
* Lower bound should point to the FIRST element not less than key.
*/
@Test
void testLowerBoundDuplicates() {
LowerBound lowerBound = new LowerBound();
Integer[] arrayWithDuplicates = {1, 2, 2, 2, 3, 4, 5};

assertEquals(1, lowerBound.find(arrayWithDuplicates, 2), "Lower bound for 2 should be at index 1 (first occurrence)");

Integer[] allSame = {2, 2, 2, 2, 2};
assertEquals(0, lowerBound.find(allSame, 2), "Lower bound for 2 in all-same array should be at index 0");
}

/**
* Test edge cases: empty array, null array, and null key.
*/
@Test
void testLowerBoundNullAndEmptyEdgeCases() {
LowerBound lowerBound = new LowerBound();
Integer[] emptyArray = {};
assertEquals(0, lowerBound.find(emptyArray, 5), "Lower bound for an empty array should be 0");
assertEquals(0, lowerBound.find(null, 5), "Lower bound for a null array should be 0");
assertEquals(0, lowerBound.find(new Integer[] {1, 2, 3}, null), "Lower bound for a null key should be 0");
}
}
15 changes: 15 additions & 0 deletions src/test/java/com/thealgorithms/searches/UpperBoundTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ void testUpperBoundMultipleValues() {
assertTrue(arrayWithDuplicates[index] > key, "Element at the upper bound index should be greater than the key.");
}

@Test
void testUpperBoundDuplicates() {
Integer[] arrayWithDuplicates = {1, 2, 2, 2, 3};
assertEquals(4, upperBound.find(arrayWithDuplicates, 2), "Upper bound for 2 in {1, 2, 2, 2, 3} should be at index 4");

Integer[] allSame = {2, 2, 2, 2, 2};
assertEquals(4, upperBound.find(allSame, 2), "Upper bound for 2 in all-same array should be at last index 4");
}

@Test
void testUpperBoundLowerThanMin() {
int key = 0; // Test with a key lower than the minimum element
Expand Down Expand Up @@ -96,4 +105,10 @@ void testUpperBoundSingleElementArray() {
index = upperBound.find(singleElementArray, 15);
assertEquals(0, index, "Upper bound for 15 in a single element array should be 0.");
}

@Test
void testUpperBoundNullArrayAndKey() {
assertEquals(0, upperBound.find(null, 5), "Upper bound for a null array should be 0.");
assertEquals(0, upperBound.find(new Integer[] {1, 2, 3}, null), "Upper bound for a null key should be 0.");
}
}
Loading