Skip to content

Commit 502f5bd

Browse files
authored
Merge pull request ByteByteGoHq#30 from Jer3myYu/java-solutions-binary-search
Java Chapter 6: Binary Search
2 parents fac15f2 + d241f98 commit 502f5bd

8 files changed

+249
-0
lines changed

java/Binary Search/CuttingWood.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import java.util.Arrays;
2+
3+
public class CuttingWood {
4+
public int cuttingwood(int[] heights, int k) {
5+
int left = 0;
6+
int right = Arrays.stream(heights).max().getAsInt();
7+
while (left < right) {
8+
// Bias the midpoint to the right during the upper-bound binary
9+
// search.
10+
int mid = left + (right - left) / 2 + 1;
11+
if (cutsEnoughWood(mid, k, heights)) {
12+
left = mid;
13+
} else {
14+
right = mid - 1;
15+
}
16+
}
17+
return right;
18+
}
19+
20+
// Determine if the current value of 'H' cuts at least 'k' meters of
21+
// wood.
22+
private boolean cutsEnoughWood(int H, int k, int[] heights) {
23+
int woodCollected = 0;
24+
for (int height : heights) {
25+
if (height > H) {
26+
woodCollected += (height - H);
27+
}
28+
}
29+
return woodCollected >= k;
30+
}
31+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
public class FindTheInsertionIndex {
2+
public int findTheInsertionIndex(int[] nums, int target) {
3+
int left = 0;
4+
int right = nums.length;
5+
while (left < right) {
6+
int mid = left + (right - left) / 2;
7+
// If the midpoint value is greater than or equal to the target,
8+
// the lower bound is either at the midpoint, or to its left.
9+
if (nums[mid] >= target) {
10+
right = mid;
11+
}
12+
// The midpoint value is less than the target, indicating the
13+
// lower bound is somewhere to the right.
14+
else {
15+
left = mid + 1;
16+
}
17+
}
18+
return left;
19+
}
20+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import java.util.Set;
2+
3+
public class FindTheMedianFromTwoSortedArrays {
4+
public float findTheMedianFromTwoSortedArrays(int[] nums1, int[] nums2) {
5+
// Optimization: ensure 'nums1' is the smaller array.
6+
if (nums2.length < nums1.length) {
7+
int[] tmp = nums1;
8+
nums1 = nums2;
9+
nums2 = tmp;
10+
}
11+
int m = nums1.length;
12+
int n = nums2.length;
13+
int halfTotalLen = (m + n) / 2;
14+
int left = 0;
15+
int right = m - 1;
16+
// A median always exists in a non-empty array, so continue binary search until
17+
// it’s found.
18+
while (true) {
19+
// Reminder: integer division rounds toward 0 in Java
20+
// ex: -1 / 2 = 0
21+
int L1Index = Math.floorDiv(left + right, 2);
22+
int L2Index = halfTotalLen - (L1Index + 1) - 1;
23+
// Set to -infinity or +infinity if out of bounds.
24+
float L1 = L1Index < 0 ? Float.NEGATIVE_INFINITY : nums1[L1Index];
25+
float R1 = L1Index >= m - 1 ? Float.POSITIVE_INFINITY : nums1[L1Index + 1];
26+
float L2 = L2Index < 0 ? Float.NEGATIVE_INFINITY : nums2[L2Index];
27+
float R2 = L2Index >= n - 1 ? Float.POSITIVE_INFINITY : nums2[L2Index + 1];
28+
// If 'L1 > R2', then 'L1' is too far to the right. Narrow the search space
29+
// toward the left.
30+
if (L1 > R2) {
31+
right = L1Index - 1;
32+
}
33+
// If 'L2 > R1', then 'L1' is too far to the left. Narrow the search space
34+
// toward the right.
35+
else if (L2 > R1) {
36+
left = L1Index + 1;
37+
}
38+
// If both 'L1' and 'L2' are less than or equal to both 'R1' and 'R2', we
39+
// found the correct slice.
40+
else {
41+
if ((m + n) % 2 == 0) {
42+
return (Math.max(L1, L2) + Math.min(R1, R2)) / 2.0;
43+
} else {
44+
return Math.min(R1, R2);
45+
}
46+
}
47+
}
48+
}
49+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
public class FindTheTargetInARotatedSortedArray {
2+
public int findTheTargetInARotatedSortedArray(int[] nums, int target) {
3+
if (nums == null || nums.length == 0) return -1;
4+
int left = 0;
5+
int right = nums.length - 1;
6+
while (left < right) {
7+
int mid = left + (right - left) / 2;
8+
if (nums[mid] == target) {
9+
return mid;
10+
}
11+
// If the left subarray [left : mid] is sorted, check if the
12+
// target falls in this range. If it does, search the left
13+
// subarray. Otherwise, search the right.
14+
else if (nums[left] <= nums[mid]) {
15+
if (nums[left] <= target && target < nums[mid]) {
16+
right = mid - 1;
17+
} else {
18+
left = mid + 1;
19+
}
20+
}
21+
// If the right subarray [mid : right] is sorted, check if the
22+
// target falls in this range. If it does, search the right
23+
// subarray. Otherwise, search the left.
24+
else {
25+
if (nums[mid] < target && target <= nums[right]) {
26+
left = mid + 1;
27+
} else {
28+
right = mid - 1;
29+
}
30+
}
31+
32+
}
33+
// If the target is found in the array, return it's index. Otherwise,
34+
// return -1.
35+
return nums[left] == target ? left : -1;
36+
}
37+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
public class FirstAndLastOccurrencesOfANumber {
2+
public int[] firstAndLastOccurrencesOfANumber(int[] nums, int target) {
3+
int lowerBound = lowerBoundBinarySearch(nums, target);
4+
int upperBound = upperBoundBinarySearch(nums, target);
5+
return new int[]{lowerBound, upperBound};
6+
}
7+
8+
private int lowerBoundBinarySearch(int[] nums, int target) {
9+
if (nums == null || nums.length == 0) return -1;
10+
int left = 0;
11+
int right = nums.length - 1;
12+
while (left < right) {
13+
int mid = left + (right - left) / 2;
14+
if (nums[mid] > target) {
15+
right = mid - 1;
16+
} else if (nums[mid] < target) {
17+
left = mid + 1;
18+
} else {
19+
right = mid;
20+
}
21+
}
22+
return nums[left] == target ? left : -1;
23+
}
24+
25+
private int upperBoundBinarySearch(int[] nums, int target) {
26+
if (nums == null || nums.length == 0) return -1;
27+
int left = 0;
28+
int right = nums.length - 1;
29+
while (left < right) {
30+
// In upper-bound binary search, bias the midpoint to the right.
31+
int mid = left + (right - left) / 2 + 1;
32+
if (nums[mid] > target) {
33+
right = mid - 1;
34+
} else if (nums[mid] < target) {
35+
left = mid + 1;
36+
} else {
37+
left = mid;
38+
}
39+
}
40+
// If the target doesn't exist in the array, then it's possible that
41+
// 'left = mid + 1' places the left pointer outside the array when
42+
// 'mid == n - 1'. So, we use the right pointer in the return
43+
// statement instead.
44+
return nums[right] == target ? right : -1;
45+
}
46+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
public class LocalMaximaInArray {
2+
public int localMaximaInArray(int[] nums) {
3+
int left = 0;
4+
int right = nums.length - 1;
5+
while (left < right) {
6+
int mid = left + (right - left) / 2;
7+
if (nums[mid] > nums[mid + 1]) {
8+
right = mid;
9+
} else {
10+
left = mid + 1;
11+
}
12+
}
13+
return left;
14+
}
15+
}

java/Binary Search/MatrixSearch.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
public class MatrixSearch {
2+
public boolean matrixSearch(int[][] matrix, int target) {
3+
int m = matrix.length;
4+
int n = matrix[0].length;
5+
int left = 0;
6+
int right = m * n - 1;
7+
// Perform binary search to find the target.
8+
while (left <= right) {
9+
int mid = left + (right - left) / 2;
10+
int r = mid / n;
11+
int c = mid % n;
12+
if (matrix[r][c] == target) {
13+
return true;
14+
} else if (matrix[r][c] > target) {
15+
right = mid - 1;
16+
} else {
17+
left = mid + 1;
18+
}
19+
}
20+
return false;
21+
}
22+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
public class WeightedRandomSelection {
2+
int[] prefixSum;
3+
4+
public WeightedRandomSelection(int[] weights) {
5+
this.prefixSum = new int[weights.length];
6+
for (int i = 0; i < weights.length; i++) {
7+
prefixSum[i] = i == 0 ? weights[i] : prefixSum[i-1] + weights[i];
8+
}
9+
}
10+
11+
private int select() {
12+
// Pick a random target between 1 and the largest endpoint on the number
13+
// line.
14+
int target = (int)(Math.random() * prefixSum[prefixSum.length - 1]) + 1;
15+
int left = 0;
16+
int right = prefixSum.length - 1;
17+
// Perform lower-bound binary search to find which endpoint (i.e., prefix
18+
// sum value) corresponds to the target.
19+
while (left < right) {
20+
int mid = left + (right - left) / 2;
21+
if (prefixSum[mid] < target) {
22+
left = mid + 1;
23+
} else {
24+
right = mid;
25+
}
26+
}
27+
return left;
28+
}
29+
}

0 commit comments

Comments
 (0)