diff --git a/src/main/java/com/thealgorithms/searches/LowerBound.java b/src/main/java/com/thealgorithms/searches/LowerBound.java
index 5a1401edd3c2..7325082c223b 100644
--- a/src/main/java/com/thealgorithms/searches/LowerBound.java
+++ b/src/main/java/com/thealgorithms/searches/LowerBound.java
@@ -13,7 +13,7 @@
* This is an extension of BinarySearch.
*
*
- * 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)
@@ -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 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 > int find(T[] array, T key) {
+ if (array == null || array.length == 0 || key == null) {
+ return 0;
+ }
return search(array, key, 0, array.length - 1);
}
@@ -51,10 +54,8 @@ private > 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
diff --git a/src/main/java/com/thealgorithms/searches/UpperBound.java b/src/main/java/com/thealgorithms/searches/UpperBound.java
index ec52c7a0ae5c..5344f22994b1 100644
--- a/src/main/java/com/thealgorithms/searches/UpperBound.java
+++ b/src/main/java/com/thealgorithms/searches/UpperBound.java
@@ -13,7 +13,7 @@
* This is an extension of BinarySearch.
*
*
- * 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)
@@ -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 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 > int find(T[] array, T key) {
+ if (array == null || array.length == 0 || key == null) {
+ return 0;
+ }
return search(array, key, 0, array.length - 1);
}
diff --git a/src/test/java/com/thealgorithms/searches/LowerBoundTest.java b/src/test/java/com/thealgorithms/searches/LowerBoundTest.java
index 30f4a5cb257c..058ea08cf614 100644
--- a/src/test/java/com/thealgorithms/searches/LowerBoundTest.java
+++ b/src/test/java/com/thealgorithms/searches/LowerBoundTest.java
@@ -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");
+ }
}
diff --git a/src/test/java/com/thealgorithms/searches/UpperBoundTest.java b/src/test/java/com/thealgorithms/searches/UpperBoundTest.java
index dc0cbdd97e19..4f5eddbe924f 100644
--- a/src/test/java/com/thealgorithms/searches/UpperBoundTest.java
+++ b/src/test/java/com/thealgorithms/searches/UpperBoundTest.java
@@ -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
@@ -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.");
+ }
}