Modified binary search [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have been trying to solve a problem where i have an array lets say A[]={5,9,11,15}; and 2 variables with values lets say 2 and 10 .i need to find whether any element of the array belong to (2,10] i.e it has value between 2 (excluded) to 10 (inclusive). i could simply turn a loop and search whether the >if(2=A[i])< but this wont work at large value of array size lets say 10^5. and also i tried using modified binary search which returns value of index less than or equal to value to key provide but failed .can anyone provide me with a fast algo for doing this?
EDIT: pos here are the number of elements breaaking is the array FLOOR is the function(modified binary)
int Floor(int A[], int l, int r, int key)
{
int m;
while( r - l > 1 )
{
m = l + (r - l)/2;
if( A[m] <= key )
l = m;
else
r = m;
}
return l;
}
int Floor(int A[], int size, int key)
{
// Error checking
if( key < A[0] )
return -1; // There is no floor value
return Floor(A, 0, size, key);
}
//
int ret=Floor(breaaking,pos,mini);
printf("%d\n",ret);
printf("mini is %d and maxi is %d",mini,maxi);
if(pos==0)
{
printf("There is no breaking point in the array :) (pos==0)\n");
printf("Yes\n");
}
else if(ret==-1)
{
printf("Mini is smaller than smallest element of breaking\n");
if(breaaking[0]<maxi)
{
printf("but maxi is greater than smallest element hece it lies between so:\n");
printf("No\n");
}
else {
printf("even maxi is less than smallest element hence:\n");
printf("Yes\n");
}
}
else if(ret==pos-1)
{
printf("mini is either equal to last element of breaker set or greater than it\n");
if(mini==breaaking[pos-1])
{
printf("mini is equal to the last element hence\n");
printf("No\n");}
else
{
printf("mini is greater than the last element hence:");
printf("Yes\n");
}
}
else
{
printf("returned a valid index which is less than or equal to mini which is btw %d\n",ret);
if(breaaking[ret]==mini)
{
printf("mini was equal to one of the element of array hence\n");
printf("No\n");
}
else
{ printf("mini is smaller than this element but greater than next element\n");
if(breaaking[ret+1]<maxi)
{
printf("next element lies between mini and maxi hence:\n") ;
printf("No\n");
}
else
{ printf("even maxi is smaller than next element hence\n");
printf("Yes\n");
}
}
`}

You can simply use std::lower_bound to return you a range that contains all values. The range will be empty, if there are none.
#include <iostream>
#include <algorithm>
#include <tuple>
template<typename ForwardIterator>
std::pair<ForwardIterator, ForwardIterator>
range_inside(ForwardIterator b, ForwardIterator end,
int lower, int upper) {
auto it = std::lower_bound(b, end, lower);
auto it2 = std::upper_bound(it, end, upper);
return std::make_pair(it, it2);
}
int main()
{
int arr[] = { 2, 5, 9, 10, 11, 15};
int *r, *e;
std::tie(r, e) = range_inside(std::begin(arr), std::end(arr), 2, 10);
std::for_each(r, e, [] (int& x) { std::cout << x << " "; });
// output: 2 5 9
return 0;
}

Related

Why doesn't this code for a binary search function in c++ work? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
#include <iostream>
int binary_search(int arr[], int size, int target)
{
int first = 0;
int last = size - 1;
int midpoint = (last + first) / 2;
while(first <= last)
{
if(arr[midpoint] == target)
{
return midpoint;
}
else if(arr[midpoint] < target)
{
first = midpoint + 1;
}
else if(arr[midpoint] > target)
{
last = midpoint - 1;
}
}
return 0;
}
int main()
{
int arr[] = {4, 12, 23, 43, 50, 60, 230, 290};
int size = sizeof(arr)/sizeof(arr[0]);
int target = 12;
std::cout << binary_search(arr, size, target);
}
if the midpoint value is lesser than the target it increases 'first' and if it's greater than the target it instead decreases 'last'. This continues until 'first' is equal to 'last'.
I saw another program where they called the function recursively but i wanted to make it work without it, what exactly am i doing wrong?
You basically forgot to update midpoint in each iteration.
An updated version of your code here (not using those "C" style arrays).It was also not clear if you meant to return the found value or the index at which it was found.
#include <iostream>
#include <vector>
auto binary_search(const std::vector<int>& values, int value)
{
std::size_t first = 0;
std::size_t last = values.size() - 1; // use vector it keeps track of its size
while (first <= last)
{
std::size_t midpoint = (last + first) / 2; // you forgot to update midpoint each loop
if (values[midpoint] == value)
{
return values[midpoint]; // <== do you want to return the position or the value?
}
if (values[midpoint] < value)
{
first = midpoint + 1;
}
else if (values[midpoint] > value)
{
last = midpoint - 1;
}
}
return 0;
}
int main()
{
std::vector<int> values{ 4, 12, 23, 43, 50, 60, 230, 290 };
std::cout << binary_search(values, 12);
return 0;
}
You always access the same value of the array arr[midpoint]
while(first <= last)
{
if(arr[midpoint] == target)
{
return midpoint;
}
else if(arr[midpoint] < target)
{
first = midpoint + 1;
}
else if(arr[midpoint] > target)
{
last = midpoint - 1;
}
}
Because you never update the value of midpoint so the conditions of your if statements will always give the same result
you wrote mid = (high+low)/2 outside while loop

Is there a more efficient way of checking whether two numbers in a list add up to an int, k?

I'm subscribed to a mailing list of coding challenges. This was today's:
Given a list of numbers and a number k, return whether any two numbers from the list add up to k.
For example, given[10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17.
Bonus: Can you do this in one pass?
I came up with the following, but I was wondering if it's the most efficient solution.
bool found = false;
int k = 17;
list<int> given({10, 15, 3, 7});
int main() {
for (int num : given) {
found = find(given.begin(), given.end(), k - num) != given.end();
if (found) break;
}
return found;
}
The code works flawlessly. I just want to know if it can be more efficient or
if I'm doing anything in my code that's frowned upon in the workplace. Many thanks.
You can iterate over the array once, using a set.
int k = 17;
list<int> given({10, 15, 3, 7});
unordered_set<int> seen();
// O(n) time-complexity
int main() {
// Iterate over O(n) items
for (int num : given) {
// O(1) operations
if (seen.contains(k - num)) {
// seen contains a value that is the difference between k and num. If you add num to that value, k - n + n = k, you have found two numbers that sum to k
return true;
} else {
// Better luck next time, keep looking
seen.add(num);
}
}
return false;
}
There is a faster solution that has complexity O(nlogn), not sure about O(n).
Hint: Use the two-pointer method.
First sort the array.
Have two pointers - One starting from index 0 and increasing, with the other starting at the last index and decreasing.
Let the one starting from 0 be a and the one starting from the last index b.
If a+b is larger than the target value, then we must decrease the index of b. Remember, the numbers before index b are smaller than the number at index b.
If a+b is smaller than the target value, we must increase the index of a, since the numbers after index a form an increasing sequence.
sort(v.begin(), v.end());
while(b>a){
if (v[a]+v[b]==target) {
//There exists such values
return 0;
}
else if (v[a]+v[b]>target) {
b--;
}
else {
a++;
}
}
Keep a map/dictionary of values "needed".
Scan through given,
Is the given value needed?
if yes, then done
else add the needed value to the needed map
Arguably, this is either O(n) or O(n log n) (depending upon map performance, and you can use a set)
pseudo-code:
bool searchy( int wanted ) {
bool found = false;
needed = map<int,bool>{};
for( each x in given ) {
if( needed[x] ) then { return found = true; }
else { needed[wanted - x] = false; }
}
return found;
}
And the algorithm in C++
#include <map>
#include <list>
int wanted = 17;
std::list<int> given({10, 15, 3, 7});
bool searchy(int wanted) {
bool found = false;
std::map<int,bool> needed = {}; //could keep position of item matched...
for (int x : given) {
if( needed.count(x) > 0 ) { found = true; break; }
else { needed[wanted - x] = false; }
}
if( found ) std::cout "found: (" << wanted - x << "+" << x << std::endl;
return found;
}
int main() {
bool found = searchy(wanted);
return found;
}
My Javascript solution using JS object (I think JS Obj serves the same as the hash map in other language). This solution memories the elements when we go through the array which can be memory expensive. But the complexity will stay as O(n).
const checkTwoSum = (arr, sum) => {
const obj = {};
const found = arr?.find(item => {
const target = sum - item;
if (obj[target]) return true;
else {
obj[item] = 1;
}
});
return !!(found || found === 0);
}

Find the kth smallest element in an unsorted array of non-negative integers

Not allowed to modify the array ( The array is read only ).
Using constant extra space is allowed.
ex:
A : [2 1 4 3 2]
k : 3
answer : 2
I did it below way. The answer is correct but need to be more memory efficient.
void insert_sorted(vector<int> &B, int a,int k)
{
for(int i=0;i<k;i++)
{
if(B[i]>=a)
{
for(int j=k-1;j>i;j--)
B[j]=B[j-1];
B[i]=a;
return;
}
}
}
int Solution::kthsmallest(const vector<int> &A, int k) {
vector <int> B;
for(int i=0;i<k;i++)
{
B.push_back(INT_MAX);
}
int l=A.size();
for(int i=0;i<l;i++)
{
if(B[k-1]>=A[i])
insert_sorted(B,A[i],k);
}
return B[k-1];
}
One possible solution is binary search.
Let A be the input array; we want to find a number b such that exactly k items in A are smaller than b.
Obviously, b must be inside the range [0, max(A)].
And we do binary search starting with this range.
Suppose we are searching within range [lo, hi].
Let c = (lo + hi)/2 which is the middle pivot.
There are three cases:
number of items in A less than c are less than k.
In this case the number we search for should be larger than c, so it should be in range (c, hi]
number of items in A less than c are larger than k.
Similarly, the number we search for is in range [lo, c)
number of items in A less than c equals to k.
In this case, the answer is the minimum element in A that is greater than or equals to c. This can be find by doing a linear search in A again
The complexity is O(n log m), where m is the max element in A.
/* assume k is 0 based, i.e. 0 <= k < n */
int kth_element(const vector<int> &A, int k){
int lo = 0, hi = *max_element(A.begin(), A.end());
while (lo <= hi){
int mid = (lo + hi) / 2;
int rank_lo = count_if(A.begin(), A.end(), [=](int i){ return i < mid;});
int rank_hi = count_if(A.begin(), A.end(), [=](int i){ return i <= mid;});
if (rank_lo <= k && k < rank_hi)
return mid;
if (k >= rank_hi)
lo = mid + 1;
else
hi = mid - 1;
}
}
Although it's not the answer to this particular problem (as it requires a modifiable collection), there is a function called std::nth_element, which rearranges the elements so that the kth element is at position k, and all elements at positions less than k are smaller than or equal to the kth element, where k is a input parameter.
The question does not ask for any time constraints. An O(nk) solution is fairly simple, by iterating the array k times (at most), and discarding one element (and its duplicates) each time.
int FindKthSmallesr(const std::vector<int>& v, int k) {
// assuming INT_MIN cannot be a value. Could be relaxed by an extra iteration.
int last_min = INT_MIN;
while (k > 0) {
int current_min = INT_MAX;
for (int x : v) {
if (x <= last_min) continue;
current_min = std::min(current_min, x);
}
last_min = current_min;
for (int x : v) {
if (x == current_min) k--;
}
}
return last_min;
}
Code on ideone: http://ideone.com/RjRIkM
If only constant extra space is allowed, we can use a simple O(n*k) algorithm.
int kth_smallest(const vector<int>& v, int k) {
int curmin = -1;
int order = -1;
while (order < k) { // while kth element wasn't reached
curmin = *min_element(v.begin(), v.end(), [curmin](int a, int b) {
if (a <= curmin) return false;
if (b <= curmin) return true;
return a < b;
}); // find minimal number among not counted yet
order += count(v.begin(), v.end(), curmin); // count all 'minimal' numbers
}
return curmin;
}
online version to play with: http://ideone.com/KNMYxA

Meximum Subarray Sum using Divide-And-Conquer

Working on an implementation of finding the Greatest Contiguous Sum of a sequence using the Divide and Conquer method as seen here.
My return value is often incorrect.
For example:
{5, 3} returns 5 instead of 8.
{-5, 3} returns 0 instead of 3.
{ 6, -5, 7 } returns 7 instead of 8.
Other notes:
decrementing or incrementing AT the first or last iterators throws an exception, saying that I either can't increment, decrement, or dereference at that point. There's a bug somewhere in GCSMid, I think, but I haven't been able to solve it.
this implementation uses random-access iterators, signified as RAIter
//function max- finds greatest number given 3 size_ts
size_t max(size_t a, size_t b, size_t c)
{
if (a >= b && a >= c)
{
return a;
}
else if (b >= a && b >= c)
{
return b;
}
else
{
return c;
}
}
//function gcsMid
//main algorithm to find subsequence if it spans across the center line
template<typename RAIter>
size_t gcsMid(RAIter first, RAIter center, RAIter last)
{
size_t sum = 0;
size_t leftSum = 0;
size_t rightSum = 0;
//to the left of center
for (RAIter i = center; i > first; i--)
{
sum += *i;
if(sum > leftSum)
{
leftSum = sum;
}
}
//to right of center
sum = 0;
for (RAIter j = (center + 1); j < last; j++)
{
sum += *j;
if (sum > rightSum)
{
rightSum = sum;
}
}
//return the sums from mid
return leftSum + rightSum;
}
//main function to call
template<typename RAIter>
int gcs(RAIter first, RAIter last)
{
size_t size = distance(first, last);
//base case is when the subarray only has 1 element. when first == last
if (first == last || size == 1)
{
if (size < 1)
{
return 0;
}
if (*first < 0)
{
return 0;
}
return *first;
}
//middle point
RAIter center = first + (size/2);
//return max of leftsum, rightsum, and midsum
return max(gcs(first, center),
gcs(center + 1, last),
gcsMid(first, center, last));
}
You have two problems with your code:
A. This loop:
for (RAIter i = center; i > first; i--)
does not include first in the loop. The reference algorithm does. You can't just use >= as the reference algorithm does as it doesn't work for iterators. Either add an extra bit of code to check first at the end, or change your loop so it somehow includes first (maybe a do while loop would suit better).
B. These definitions:
size_t sum = 0;
size_t leftSum = 0;
size_t rightSum = 0;
should not be size_t as size_t is unsigned. This means that when the sum goes negative, checks like if(sum > leftSum) no longer work, as the negative value (which underflows) is bigger than the positive value.
Change them to int.
The best way to find these kinds of errors is to run the code through a debugger. You can then step through each line of your code and see what the variable values are. This makes it easy to spot things like negative numbers becoming large positive numbers as above.

How to check if a number exists between two given positions in fastest way?

I'm given a number say N and its corresponding positions in an Array.
Say the positions (indices) given are:
4 5 8 11 13 15 21 28
I'm given two positions (indices) say x and y. Let x=7 and y=13.
I need to find how many occurrences of number is there between x and y (both included, y>=x). Like in above example the number exists at positions 8,11 and 13 which lies between positions x and y and thus answer is 3.
A simple approach would be the naive O(n) algorithm but I want to take advantage of fact that the poistions will always be given in ascending order. I think applying binary search in a modified manner can help but I'm facing facing trouble.
// P is the array that stores positions(indices) of number
int start=0,End=n-1; // n is the size of array P
int mid=(start+End)/2;
int pos1=0,pos2=0;
while(End>start)
{
mid=(start+End)/2;
if(P[mid]>=x && P[mid-1]<x && flag1!=0)
{
pos1=mid;
flag1=0
}
if(P[mid]<=y && P[mid+1]>y && flag2!=0)
{
pos2=mid;
flag2=0;
}
else if (P[mid]<x)
start=mid;
else
End=mid;
}
int Number_Of_Occurence=(pos2-pos1);
Can you please suggest where my code may go wrong?
You can take the advantage of STL library. std::lower_bound or std::upper_bound comes to mind.
Both have logarithmic complexity on sorted containers with random iterators.
For example:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {4, 5, 7, 8, 11, 13, 15, 21, 28};
int low_value = 7;
int high_value = 13;
auto low = std::lower_bound(v.begin(), v.end(), low_value);
auto high = std::upper_bound(v.begin(), v.end(), high_value);
std::cout << std::distance(low, high) << " elements in interval ["
<< low_value << ", " << high_value << "]" << std::endl;
return 0;
}
I'm boldly assuming this isn't a homework problem... you need to find the indices of both endpoints however your code only has one "mid" variable. Assuming you reimplement the binary search for both endpoints correctly and you are worried about number of operations, you can re-order the conditional in the if statements so that they short-circuit on flag!=0 before checking two other conditions. ie:
if( !flag1 && P[mid1]>=x && P[mid1-1]<x ) {...}
is technically faster than
if( P[mid1]>=x && P[mid1-1]<x && !flag1 ) {...}
Next, division can be an expensive operation ... and you are dividing by 2. Use a bit shift instead:
jump_size = jump_size >> 2
Now throwing away the flag entirely, we might rewrite the code to look more like this:
// n is the size of array P
// start int the middle
int pos1=pos2=n>>2;
// jump size is how far we jump up or down looking for our index
int jump_size=pos1>>2;
while(jump_size)
{
if(P[pos1]>x) { pos1 -= jump_size; }
else if(P[pos1]<x) { pos1+=jump_size; }
// similar for y and pos2
jump_size=jump_size>>2;
}
you can use floor(x)-ceil(y) to find it in O(log N) time .
below is code for finding ceil()..
int ceilSearch(int arr[], int low, int high, int x)
{
int i;
/* If x is smaller than or equal to first element,
then return the first element */
if(x <= arr[low])
return low;
/* Otherwise, linearly search for ceil value */
for(i = low; i < high; i++)
{
if(arr[i] == x)
return i;
/* if x lies between arr[i] and arr[i+1] including
arr[i+1], then return arr[i+1] */
if(arr[i] < x && arr[i+1] >= x)
return i+1;
}
/* If we reach here then x is greater than the last element
of the array, return -1 in this case */
return -1;
}
You can easily modify it to make floor() function .
Another method is to use lower_bound() and upper_bound() as you are using c++ .