Skip to content

Commit 0a210ff

Browse files
committed
Add Binary Search Solutions
1 parent 77cb109 commit 0a210ff

8 files changed

+213
-0
lines changed

kotlin/Binary Search/CuttingWood.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
fun cuttingWood(heights: List<Int>, k: Int): Int {
2+
var left = 0
3+
var right = heights.maxOrNull()!!
4+
while (left < right) {
5+
// Bias the midpoint to the right during the upper-bound binary
6+
// search.
7+
val mid = (left + (right - left) / 2) + 1
8+
if (cutsEnoughWood(mid, k, heights)) {
9+
left = mid
10+
} else {
11+
right = mid - 1
12+
}
13+
}
14+
return right
15+
}
16+
17+
// Determine if the current value of 'H' cuts at least 'k' meters of
18+
// wood.
19+
fun cutsEnoughWood(H: Int, k: Int, heights: List<Int>): Boolean {
20+
var woodCollected = 0
21+
for (height in heights) {
22+
if (height > H) {
23+
woodCollected += height - H
24+
}
25+
}
26+
return woodCollected >= k
27+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
fun findTheInsertionIndex(nums: List<Int>, target: Int): Int {
2+
var left = 0
3+
var right = nums.size
4+
while (left < right) {
5+
val mid = left + (right - left) / 2
6+
// If the midpoint value is greater than or equal to the target,
7+
// the lower bound is either at the midpoint, or to its left.
8+
if (nums[mid] >= target) {
9+
right = mid
10+
// The midpoint value is less than the target, indicating the
11+
// lower bound is somewhere to the right.
12+
} else {
13+
left = mid + 1
14+
}
15+
}
16+
return left
17+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
fun findTheMedianFromTwoSortedArrays(nums1: List<Int>, nums2: List<Int>): Double {
2+
val m = nums1.size
3+
val n = nums2.size
4+
// Ensure 'nums1' is the smaller array.
5+
if (m > n) {
6+
return findTheMedianFromTwoSortedArrays(nums2, nums1)
7+
}
8+
var left = 0
9+
var right = m - 1
10+
val halfTotalLen = (m + n) / 2
11+
// A median always exists in a non-empty array, so continue binary search until
12+
// it’s found.
13+
while (true) {
14+
val L1Index = (left + right) / 2
15+
val L2Index = halfTotalLen - (L1Index + 1) - 1
16+
// Set to -infinity or +infinity if out of bounds.
17+
val L1 = if (L1Index < 0) Double.MIN_VALUE else nums1[L1Index].toDouble()
18+
val R1 = if (L1Index >= m - 1) Double.MAX_VALUE else nums1[L1Index + 1].toDouble()
19+
val L2 = if (L2Index < 0) Double.MIN_VALUE else nums2[L2Index].toDouble()
20+
val R2 = if (L2Index >= n - 1) Double.MAX_VALUE else nums2[L2Index + 1].toDouble()
21+
// If 'L1 > R2', then 'L1' is too far to the right. Narrow the search space
22+
// toward the left.
23+
if (L1 > R2) {
24+
right = L1Index - 1
25+
// If 'L2 > R1', then 'L1' is too far to the left. Narrow the search space
26+
// toward the right.
27+
} else if (L2 > R1) {
28+
left = L1Index + 1
29+
// If both 'L1' and 'L2' are less than or equal to both 'R1' and 'R2', we
30+
// found the correct slice.
31+
} else {
32+
return if ((m + n) % 2 == 0) {
33+
(maxOf(L1, L2) + minOf(R1, R2)) / 2.0
34+
} else {
35+
minOf(R1, R2)
36+
}
37+
}
38+
}
39+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
fun findTheTargetInARotatedSortedArray(nums: List<Int>, target: Int): Int {
2+
var left = 0
3+
var right = nums.size - 1
4+
while (left < right) {
5+
val mid = left + (right - left) / 2
6+
if (nums[mid] == target) {
7+
return mid
8+
}
9+
// If the left subarray [left : mid] is sorted, check if the
10+
// target falls in this range. If it does, search the left
11+
// subarray. Otherwise, search the right.
12+
if (nums[left] <= nums[mid]) {
13+
if (nums[left] <= target && target < nums[mid]) {
14+
right = mid - 1
15+
} else {
16+
left = mid + 1
17+
}
18+
// If the right subarray [mid : right] is sorted, check if the
19+
// target falls in this range. If it does, search the right
20+
// subarray. Otherwise, search the left.
21+
} else {
22+
if (nums[mid] < target && target <= nums[right]) {
23+
left = mid + 1
24+
} else {
25+
right = mid - 1
26+
}
27+
}
28+
}
29+
return if (nums.isNotEmpty() && nums[left] == target) left else -1
30+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
fun firstAndLastOccurrencesOfANumber(nums: List<Int>, target: Int): List<Int> {
2+
val lowerBound = lowerBoundBinarySearch(nums, target)
3+
val upperBound = upperBoundBinarySearch(nums, target)
4+
return listOf(lowerBound, upperBound)
5+
}
6+
7+
fun lowerBoundBinarySearch(nums: List<Int>, target: Int): Int {
8+
var left = 0
9+
var right = nums.size - 1
10+
while (left < right) {
11+
val mid = left + (right - left) / 2
12+
when {
13+
nums[mid] > target -> right = mid - 1
14+
nums[mid] < target -> left = mid + 1
15+
else -> right = mid
16+
}
17+
}
18+
return if (nums.isNotEmpty() && nums[left] == target) left else -1
19+
}
20+
21+
fun upperBoundBinarySearch(nums: List<Int>, target: Int): Int {
22+
var left = 0
23+
var right = nums.size - 1
24+
while (left < right) {
25+
// In upper-bound binary search, bias the midpoint to the right.
26+
val mid = (left + (right - left) / 2) + 1
27+
when {
28+
nums[mid] > target -> right = mid - 1
29+
nums[mid] < target -> left = mid + 1
30+
else -> left = mid
31+
}
32+
}
33+
// If the target doesn't exist in the array, then it's possible that
34+
// 'left = mid + 1' places the left pointer outside the array when
35+
// 'mid == n - 1'. So, we use the right pointer in the return
36+
// statement instead.
37+
return if (nums.isNotEmpty() && nums[right] == target) right else -1
38+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fun localMaximaInArray(nums: List<Int>): Int {
2+
var left = 0
3+
var right = nums.size - 1
4+
while (left < right) {
5+
val mid = left + (right - left) / 2
6+
if (nums[mid] > nums[mid + 1]) {
7+
right = mid
8+
} else {
9+
left = mid + 1
10+
}
11+
}
12+
return left
13+
}

kotlin/Binary Search/MatrixSearch.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
fun matrixSearch(matrix: List<List<Int>>, target: Int): Boolean {
2+
val m = matrix.size
3+
val n = matrix[0].size
4+
var left = 0
5+
var right = m * n - 1
6+
// Perform binary search to find the target.
7+
while (left <= right) {
8+
val mid = left + (right - left) / 2
9+
val r = mid / n
10+
val c = mid % n
11+
if (matrix[r][c] == target) {
12+
return true
13+
} else if (matrix[r][c] > target) {
14+
right = mid - 1
15+
} else {
16+
left = mid + 1
17+
}
18+
}
19+
return false
20+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class WeightedRandomSelection(private val weights: IntArray) {
2+
private val prefixSums = IntArray(weights.size)
3+
4+
init {
5+
prefixSums[0] = weights[0]
6+
for (i in 1 until weights.size) {
7+
prefixSums[i] = prefixSums[i - 1] + weights[i]
8+
}
9+
}
10+
11+
fun select(): Int {
12+
// Pick a random target between 1 and the largest endpoint on the number
13+
// line.
14+
val target = (1..prefixSums.last()).random()
15+
var left = 0
16+
var right = prefixSums.size - 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+
val mid = left + (right - left) / 2
21+
if (prefixSums[mid] < target) {
22+
left = mid + 1
23+
} else {
24+
right = mid
25+
}
26+
}
27+
return left
28+
}
29+
}

0 commit comments

Comments
 (0)