Skip to content

cleanup: Improve docs, safety, and readability in RangeInSortedArray #6361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
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
78 changes: 61 additions & 17 deletions src/main/java/com/thealgorithms/misc/RangeInSortedArray.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,46 @@
package com.thealgorithms.misc;

/**
* Utility class for operations to find the range of occurrences of a key
* in a sorted (non-decreasing) array, and to count elements less than or equal to a given key.
*/
public final class RangeInSortedArray {

private RangeInSortedArray() {
}

// Get the 1st and last occurrence index of a number 'key' in a non-decreasing array 'nums'
// Gives [-1, -1] in case element doesn't exist in array
/**
* Finds the first and last occurrence indices of the key in a sorted array.
*
* @param nums sorted array of integers (non-decreasing order)
* @param key the target value to search for
* @return int array of size two where
* - index 0 is the first occurrence of key,
* - index 1 is the last occurrence of key,
* or [-1, -1] if the key does not exist in the array.
*/
public static int[] sortedRange(int[] nums, int key) {
int[] range = new int[] {-1, -1};
alteredBinSearchIter(nums, key, 0, nums.length - 1, range, true);
alteredBinSearchIter(nums, key, 0, nums.length - 1, range, false);
alteredBinSearchIter(nums, key, 0, nums.length - 1, range, true); // find left boundary
alteredBinSearchIter(nums, key, 0, nums.length - 1, range, false); // find right boundary
return range;
}

// Recursive altered binary search which searches for leftmost as well as rightmost occurrence
// of 'key'
/**
* Recursive altered binary search to find either the leftmost or rightmost occurrence of a key.
*
* @param nums the sorted array
* @param key the target to find
* @param left current left bound in search
* @param right current right bound in search
* @param range array to update with boundaries: range[0] for leftmost, range[1] for rightmost
* @param goLeft if true, searches for leftmost occurrence; if false, for rightmost occurrence
*/
public static void alteredBinSearch(int[] nums, int key, int left, int right, int[] range, boolean goLeft) {
if (left > right) {
return;
}
int mid = (left + right) >>> 1;
int mid = left + ((right - left) >>> 1);
if (nums[mid] > key) {
alteredBinSearch(nums, key, left, mid - 1, range, goLeft);
} else if (nums[mid] < key) {
Expand All @@ -41,11 +62,19 @@ public static void alteredBinSearch(int[] nums, int key, int left, int right, in
}
}

// Iterative altered binary search which searches for leftmost as well as rightmost occurrence
// of 'key'
/**
* Iterative altered binary search to find either the leftmost or rightmost occurrence of a key.
*
* @param nums the sorted array
* @param key the target to find
* @param left initial left bound
* @param right initial right bound
* @param range array to update with boundaries: range[0] for leftmost, range[1] for rightmost
* @param goLeft if true, searches for leftmost occurrence; if false, for rightmost occurrence
*/
public static void alteredBinSearchIter(int[] nums, int key, int left, int right, int[] range, boolean goLeft) {
while (left <= right) {
final int mid = (left + right) >>> 1;
int mid = left + ((right - left) >>> 1);
if (nums[mid] > key) {
right = mid - 1;
} else if (nums[mid] < key) {
Expand All @@ -55,33 +84,48 @@ public static void alteredBinSearchIter(int[] nums, int key, int left, int right
if (mid == 0 || nums[mid - 1] != key) {
range[0] = mid;
return;
} else {
right = mid - 1;
}
right = mid - 1;
} else {
if (mid == nums.length - 1 || nums[mid + 1] != key) {
range[1] = mid;
return;
} else {
left = mid + 1;
}
left = mid + 1;
}
}
}
}

/**
* Counts the number of elements strictly less than the given key.
*
* @param nums sorted array
* @param key the key to compare
* @return the count of elements less than the key
*/
public static int getCountLessThan(int[] nums, int key) {
return getLessThan(nums, key, 0, nums.length - 1);
}

/**
* Helper method using binary search to count elements less than or equal to the key.
*
* @param nums sorted array
* @param key the key to compare
* @param left current left bound
* @param right current right bound
* @return count of elements less than or equal to the key
*/
public static int getLessThan(int[] nums, int key, int left, int right) {
int count = 0;
while (left <= right) {
final int mid = (left + right) >>> 1;
int mid = left + ((right - left) >>> 1);
if (nums[mid] > key) {
right = mid - 1;
} else if (nums[mid] <= key) {
count = mid + 1; // At least mid+1 elements exist which are <= key
} else {
// nums[mid] <= key
count = mid + 1; // all elements from 0 to mid inclusive are <= key
left = mid + 1;
}
}
Expand Down
Loading