Skip to content

Commit 77cb109

Browse files
authored
Merge pull request ByteByteGoHq#20 from ongshunping/cpp-solutions-binary-search
Add C++ solutions for Chapter 6 (Binary Search)
2 parents e193529 + 3e35697 commit 77cb109

8 files changed

+245
-0
lines changed

cpp/Binary Search/cutting_wood.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <vector>
2+
#include <algorithm>
3+
4+
int cuttingWood(std::vector<int>& heights, int k) {
5+
int left = 0;
6+
int right = *std::max_element(heights.begin(), heights.end());
7+
while (left < right) {
8+
// Bias the midpoint to the right during the upper-bound binary
9+
// search.
10+
int mid = (left + right) / 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+
bool cutsEnoughWood(int H, int k, std::vector<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+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <vector>
2+
3+
int findTheInsertionIndex(std::vector<int>& nums, int target) {
4+
int left = 0;
5+
int right = nums.size();
6+
while (left < right) {
7+
int mid = (left + right) / 2;
8+
// If the midpoint value is greater than or equal to the target,
9+
// the lower bound is either at the midpoint, or to its left.
10+
if (nums[mid] >= target) {
11+
right = mid;
12+
}
13+
// The midpoint value is less than the target, indicating the
14+
// lower bound is somewhere to the right.
15+
else {
16+
left = mid + 1;
17+
}
18+
}
19+
return left;
20+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <vector>
2+
#include <algorithm>
3+
#include <limits>
4+
#include <cmath>
5+
6+
double findTheMedianFromTwoSortedArrays(std::vector<int>& nums1, std::vector<int>& nums2) {
7+
// Optimization: ensure 'nums1' is the smaller array.
8+
if (nums2.size() < nums1.size()) {
9+
std::swap(nums1, nums2);
10+
}
11+
int m = nums1.size();
12+
int n = nums2.size();
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+
// Use std::floor with floating-point division to ensure correct rounding down
20+
// when left + right is negative, avoiding issues with integer division.
21+
int L1Index = std::floor((left + right) / 2.0);
22+
int L2Index = halfTotalLen - (L1Index + 1) - 1;
23+
// Set to -infinity or +infinity if out of bounds.
24+
double L1 = (L1Index < 0) ? -std::numeric_limits<double>::infinity() : nums1[L1Index];
25+
double R1 = (L1Index >= m - 1) ? std::numeric_limits<double>::infinity() : nums1[L1Index + 1];
26+
double L2 = (L2Index < 0) ? -std::numeric_limits<double>::infinity() : nums2[L2Index];
27+
double R2 = (L2Index >= n - 1) ? std::numeric_limits<double>::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 (std::max(L1, L2) + std::min(R1, R2)) / 2.0;
43+
} else {
44+
return std::min(R1, R2);
45+
}
46+
}
47+
}
48+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <vector>
2+
3+
int findTheTargetInARotatedSortedArray(std::vector<int>& nums, int target) {
4+
int left = 0, right = nums.size() - 1;
5+
while (left < right) {
6+
int mid = (left + right) / 2;
7+
if (nums[mid] == target) {
8+
return mid;
9+
}
10+
// If the left subarray [left : mid] is sorted, check if the
11+
// target falls in this range. If it does, search the left
12+
// subarray. Otherwise, search the right.
13+
else if (nums[left] <= nums[mid]) {
14+
if (nums[left] <= target && target < nums[mid]) {
15+
right = mid - 1;
16+
} else {
17+
left = mid + 1;
18+
}
19+
}
20+
// If the right subarray [mid : right] is sorted, check if the
21+
// target falls in this range. If it does, search the right
22+
// subarray. Otherwise, search the left.
23+
else {
24+
if (nums[mid] < target && target <= nums[right]) {
25+
left = mid + 1;
26+
} else {
27+
right = mid - 1;
28+
}
29+
}
30+
}
31+
// If the target is found in the array, return its index. Otherwise,
32+
// return -1.
33+
return nums[left] == target ? left : -1;
34+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <vector>
2+
3+
std::vector<int> firstAndLastOccurrencesOfANumber(std::vector<int>& nums, int target) {
4+
int lowerBound = lowerBoundBinarySearch(nums, target);
5+
int upperBound = upperBoundBinarySearch(nums, target);
6+
return {lowerBound, upperBound};
7+
}
8+
9+
int lowerBoundBinarySearch(std::vector<int>& nums, int target) {
10+
int left = 0, right = nums.size() - 1;
11+
while (left < right) {
12+
int mid = (left + right) / 2;
13+
if (nums[mid] > target) {
14+
right = mid - 1;
15+
} else if (nums[mid] < target) {
16+
left = mid + 1;
17+
} else {
18+
right = mid;
19+
}
20+
}
21+
return !nums.empty() && nums[left] == target ? left : -1;
22+
}
23+
24+
int upperBoundBinarySearch(std::vector<int>& nums, int target) {
25+
int left = 0, right = nums.size() - 1;
26+
while (left < right) {
27+
// In upper-bound binary search, bias the midpoint to the right.
28+
int mid = (left + right) / 2 + 1;
29+
if (nums[mid] > target) {
30+
right = mid - 1;
31+
} else if (nums[mid] < target) {
32+
left = mid + 1;
33+
} else {
34+
left = mid;
35+
}
36+
}
37+
// If the target doesn't exist in the array, then it's possible that
38+
// 'left = mid + 1' places the left pointer outside the array when
39+
// 'mid == n - 1'. So, we use the right pointer in the return
40+
// statement instead.
41+
return !nums.empty() && nums[right] == target ? right : -1;
42+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <vector>
2+
3+
int localMaximaInArray(std::vector<int>& nums) {
4+
int left = 0, right = nums.size() - 1;
5+
while (left < right) {
6+
int mid = (left + right) / 2;
7+
if (nums[mid] > nums[mid + 1]) {
8+
right = mid;
9+
} else {
10+
left = mid + 1;
11+
}
12+
}
13+
return left;
14+
}

cpp/Binary Search/matrix_search.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <vector>
2+
3+
bool matrixSearch(std::vector<std::vector<int>>& matrix, int target) {
4+
int m = matrix.size(), n = matrix[0].size();
5+
int left = 0, right = m * n - 1;
6+
// Perform binary search to find the target.
7+
while (left <= right) {
8+
int mid = (left + right) / 2;
9+
int r = mid / n;
10+
int 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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <vector>
2+
#include <random>
3+
4+
class WeightedRandomSelection {
5+
public:
6+
std::vector<int> prefixSums;
7+
int totalWeight;
8+
std::mt19937 rng;
9+
std::uniform_int_distribution<int> dist;
10+
WeightedRandomSelection(std::vector<int>& weights) : rng(std::random_device{}()) {
11+
prefixSums.resize(weights.size());
12+
prefixSums[0] = weights[0];
13+
for (int i = 1; i < weights.size(); i++) {
14+
prefixSums[i] = prefixSums[i - 1] + weights[i];
15+
}
16+
totalWeight = prefixSums.back();
17+
dist = std::uniform_int_distribution<int>(1, totalWeight);
18+
}
19+
20+
int select() {
21+
// Pick a random target between 1 and the largest endpoint on the number
22+
// line.
23+
int target = dist(rng);
24+
int left = 0, right = prefixSums.size() - 1;
25+
// Perform lower-bound binary search to find which endpoint (i.e., prefix
26+
// sum value) corresponds to the target.
27+
while (left < right) {
28+
int mid = (left + right) / 2;
29+
if (prefixSums[mid] < target) {
30+
left = mid + 1;
31+
} else {
32+
right = mid;
33+
}
34+
}
35+
return left;
36+
}
37+
};

0 commit comments

Comments
 (0)