Skip to content

Commit e3e6cbd

Browse files
committed
Test and fix lower bound
Has no impact on solving the test cases for the problem, but was not the correct implementation of lower bound using binary search.
1 parent 8d8f1fb commit e3e6cbd

File tree

1 file changed

+96
-12
lines changed

1 file changed

+96
-12
lines changed

algorithms/binary_search/ice_cream/ice_cream.cpp

Lines changed: 96 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#include <cmath>
22
#include <cstdio>
3-
#include <vector>
4-
#include <iostream>
3+
#include <ctime>
54
#include <algorithm>
5+
#include <iostream>
6+
#include <vector>
67
using namespace std;
78

89
struct element {
@@ -14,29 +15,112 @@ struct element {
1415
}
1516
};
1617

17-
size_t lower_bound(const vector<element>& flavors, const int search) {
18-
if (flavors.empty()) {
19-
return -1;
18+
template <typename T>
19+
size_t lower_bound(const vector<T>& arr, const T& search) {
20+
if (arr.empty()) {
21+
return arr.size();
2022
}
2123

24+
// binary search
2225
size_t begin = 0;
23-
size_t end = flavors.size();
24-
while (begin + 1 != end) {
26+
size_t end = arr.size() - 1;
27+
while (begin < end) {
2528
// (begin + end) / 2 can cause overflow
2629
size_t middle = begin + (end - begin) / 2;
27-
if (search < flavors[middle].value) {
30+
if (arr[middle] < search) {
31+
// search right half
32+
begin = middle + 1;
33+
} else {
2834
// search left half
2935
end = middle;
30-
} else {
31-
// search right half
32-
begin = middle;
3336
}
3437
}
3538

39+
// all values are less than search
40+
if (arr[begin] < search) {
41+
return arr.size();
42+
}
3643
return begin;
3744
}
3845

46+
template <typename T>
47+
size_t linear_scan_lower_bound(const vector<T>& arr, const T& search) {
48+
size_t i = 0;
49+
for ( ; i < arr.size(); i++) {
50+
if (!(arr[i] < search)) {
51+
return i;
52+
}
53+
}
54+
return arr.size();
55+
}
56+
57+
void test(vector<int>& arr, int search) {
58+
size_t linear = linear_scan_lower_bound(arr, search);
59+
size_t bsearch = lower_bound(arr, search);
60+
auto it = std::lower_bound(arr.begin(), arr.end(), search);
61+
size_t std = it - arr.begin();
62+
if (linear != bsearch || std != bsearch) {
63+
cout << "key = " << search << endl
64+
<< "linear = " << linear << endl
65+
<< "binary = " << bsearch << endl
66+
<< "lower_bound = " << std << endl;
67+
if (arr.size() <= 100) {
68+
for (auto a : arr) {
69+
cout << a << ' ';
70+
}
71+
}
72+
cout << endl << endl;
73+
}
74+
}
75+
76+
void test_lower_bound() {
77+
// fixed test cases
78+
{
79+
vector<int> arr = {};
80+
for (int i = 0; i <= 7; i++) {
81+
test(arr, i);
82+
}
83+
}
84+
{
85+
vector<int> arr = {2};
86+
for (int i = 0; i <= 7; i++) {
87+
test(arr, i);
88+
}
89+
}
90+
{
91+
vector<int> arr = {2, 5};
92+
for (int i = 0; i <= 7; i++) {
93+
test(arr, i);
94+
}
95+
}
96+
{
97+
vector<int> arr = {5, 10, 15, 20, 25, 30};
98+
for (int i = 0; i <= 35; i++) {
99+
test(arr, i);
100+
}
101+
}
102+
103+
// randomized test cases
104+
srand(time(NULL));
105+
{
106+
const auto max = 10000;
107+
vector<int> arr;
108+
arr.reserve(max);
109+
const auto tries = 1000 * 1000;
110+
for (int t = 0; t < tries; t++) {
111+
arr.clear();
112+
auto currmax = rand() % max;
113+
for (int i = 0; i < max; i++) {
114+
arr.push_back(rand() % max);
115+
}
116+
sort(arr.begin(), arr.end());
117+
test(arr, rand() % max);
118+
}
119+
}
120+
}
121+
39122
int main() {
123+
if (false) { test_lower_bound(); return 0; }
40124
int T = 0;
41125
cin >> T;
42126
for (int t = 0; t < T; t++) {
@@ -56,7 +140,7 @@ int main() {
56140
sort(flavors.begin(), flavors.end());
57141
for (auto flavor : flavors) {
58142
int need = M - flavor.value;
59-
size_t lbound = lower_bound(flavors, need);
143+
size_t lbound = lower_bound(flavors, {need, 0});
60144
if (lbound != -1) {
61145
auto& other_flavor = flavors[lbound];
62146
if (other_flavor.value == need && flavor.index != other_flavor.index) {

0 commit comments

Comments
 (0)