Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.thealgorithms.searches;

/**
* Binary Search implementation specifically for String arrays
* This algorithm finds the position of a target string within a sorted string array
*
* Time Complexity: O(log n * m) where n is array length and m is average string length
* Space Complexity: O(1)
*
* @see <a href="https://en.wikipedia.org/wiki/Binary_search_algorithm">Binary Search Algorithm</a>
* @author Jeevan Yewale (https://github.com/JeevanYewale)
*/
public final class BinarySearchStrings {

private BinarySearchStrings() {
// Utility class
}

/**
* Performs binary search on a sorted string array
*
* @param array sorted array of strings (must be sorted in lexicographical order)
* @param target the string to search for
* @return index of target string if found, -1 otherwise
*/
public static int search(String[] array, String target) {
if (array == null || array.length == 0 || target == null) {
return -1;
}

int left = 0;
int right = array.length - 1;

while (left <= right) {
int mid = left + (right - left) / 2;
int comparison = target.compareTo(array[mid]);

if (comparison == 0) {
return mid; // Found the target
} else if (comparison < 0) {
right = mid - 1; // Target is in left half
} else {
left = mid + 1; // Target is in right half
}
}

return -1; // Target not found
}

/**
* Performs case-insensitive binary search on a sorted string array
*
* @param array sorted array of strings (must be sorted in lexicographical order, case-insensitive)
* @param target the string to search for
* @return index of target string if found, -1 otherwise
*/
public static int searchIgnoreCase(String[] array, String target) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic here is 100% identical to the search method above.

Please refactor this to use a private helper method that accepts a Comparator. That way you don't duplicate the binary search code twice.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@singhc7 Thank you for the detailed review! You're absolutely right on all points:

  1. Memory optimization: Replaced targetLower.compareTo(array[mid].toLowerCase()) with target.compareToIgnoreCase(array[mid]) to avoid unnecessary String object creation.

  2. Code deduplication: Refactored both methods to use a private binarySearch(String[] array, String target, Comparator<String> comparator) helper method. Now search() uses String::compareTo and searchIgnoreCase() uses String::compareToIgnoreCase.

  3. Formatting: Will run clang-format before the next push.

The refactored code is much cleaner and more efficient. Thanks for the guidance!

if (array == null || array.length == 0 || target == null) {
return -1;
}

int left = 0;
int right = array.length - 1;
String targetLower = target.toLowerCase();

while (left <= right) {
int mid = left + (right - left) / 2;
int comparison = targetLower.compareTo(array[mid].toLowerCase());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

array[mid].toLowerCase() allocates a new String object every single iteration. That's heavy on memory.

You should just use target.compareToIgnoreCase(array[mid]) here instead.


if (comparison == 0) {
return mid; // Found the target
} else if (comparison < 0) {
right = mid - 1; // Target is in left half
} else {
left = mid + 1; // Target is in right half
}
}

return -1; // Target not found
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.thealgorithms.searches;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

/**
* Test cases for BinarySearchStrings algorithm
*
* @author Jeevan Yewale (https://github.com/JeevanYewale)
*/
class BinarySearchStringsTest {

@Test
void testBasicSearch() {
String[] array = {"apple", "banana", "cherry", "date", "elderberry"};

assertEquals(0, BinarySearchStrings.search(array, "apple"));
assertEquals(2, BinarySearchStrings.search(array, "cherry"));
assertEquals(4, BinarySearchStrings.search(array, "elderberry"));
assertEquals(-1, BinarySearchStrings.search(array, "grape"));
}

@Test
void testEmptyArray() {
String[] array = {};
assertEquals(-1, BinarySearchStrings.search(array, "test"));
}

@Test
void testNullArray() {
assertEquals(-1, BinarySearchStrings.search(null, "test"));
}

@Test
void testNullTarget() {
String[] array = {"apple", "banana"};
assertEquals(-1, BinarySearchStrings.search(array, null));
}

@Test
void testSingleElement() {
String[] array = {"single"};
assertEquals(0, BinarySearchStrings.search(array, "single"));
assertEquals(-1, BinarySearchStrings.search(array, "other"));
}

@Test
void testCaseInsensitiveSearch() {
String[] array = {"apple", "banana", "cherry", "date", "elderberry"};

assertEquals(0, BinarySearchStrings.searchIgnoreCase(array, "APPLE"));
assertEquals(2, BinarySearchStrings.searchIgnoreCase(array, "Cherry"));
assertEquals(-1, BinarySearchStrings.searchIgnoreCase(array, "GRAPE"));
}
}
Loading