https://leetcode.com/problems/search-in-rotated-sorted-array/
The question requires that the solution be O(log n) and I believe that my solution is O(log n) since my process of finding the smallest element is O(log n) and then using binary search to find the target value is also O(log n). However, my code is exceeding the time limit.
int search(vector<int>& nums, int target) {
if(nums.size() == 0){
return -1;
}
int left = 0;
int right = nums.size() - 1;
while(left < right){
int middle = left + (right - left) / 2;
if(nums[left] < nums[middle]){
left = middle;
}
else{
right = middle;
}
}
if(target >= nums[0]){
return binarySearch(nums, target, 0, left - 1);
}
else{
return binarySearch(nums, target, left, nums.size() - 1);
}
}
int binarySearch(vector<int>& nums, int target, int start, int end){
if(nums.size() == 0 || (start == end && nums[start] != target)){
return -1;
}
int mid = start + (end - start) / 2;
if(nums[mid] == target){
return mid;
}
if(nums[mid] > target){
return binarySearch(nums, target, start, mid - 1);
}
else{
return binarySearch(nums, target, mid, end);
}
}
I believe binarySearch can run into an endless loop. When end = start + 1 you will get mid = start so if nums[start] < target you end up making a recursive call with the same parameters as before.
Related
how can I change these two (or either of them) functions to get the minimum dist where dist=pow(target-v[i],2). I want to get the index of the element in the vector with the smallest distance from target considering that the vector is ordered and I want to find the element efficiently using binary search.
Thanks a lot.
int getClosest(int val1, int val2,int target, int i, int j)
{
if (pow(target - val1,2) >= pow(val2 - target,2))
return j;
else
return i;
}
// Returns element closest to target
int findClosest(vector<int> arr, int n, int target)
{
// Corner cases
if (target <= arr[0])
return 0;
if (target >= arr[n - 1])
return n - 1;
// Doing binary search
int i = 0, j = n, mid = 0;
while (i < j) {
mid = (i + j) / 2;
if (arr[mid] == target)
return mid;
/* If target is less than array element,
then search in left */
if (target < arr[mid]) {
// If target is greater than previous
// to mid, return closest of two
if (mid > 0 && target > arr[mid - 1])
{
return getClosest(arr[mid - 1],arr[mid], target, mid-1,mid);
}
/* Repeat for left half */
j = mid;
}
// If target is greater than mid
else {
if (mid < n - 1 && target < arr[mid + 1])
return getClosest(arr[mid], arr[mid + 1], target, mid,mid+1);
// update i
i = mid + 1;
}
}
// Only single element left after search
return mid;
}
enter code here
First of all, to use binary search algorithm, you must be sure about the given array or the vector is sorted or not. If the vector is sorted then only you can apply binary search to find the index of the closest distance.
Now considering the given vector is sorted, we can apply binary search.
Another thing that I see in your code, into the getClosest(int v1, int v2, int target, int i, int j) method that you are squaring both side to check with the positive integers. Rather you can consider mod operator or abs method in cpp to do so. abs will take less time rather than pow.
Modified Code:
int getClosest(int val1, int val2,int target, int i, int j)
{
if (abs(target - val1) >= abs(val2 - target))
return j;
else
return i;
}
// Returns element closest to target
int findClosest(vector<int> arr, int n, int target)
{
// Corner cases
if (target <= arr[0])
return 0;
if (target >= arr[n - 1])
return n - 1;
// Doing binary search
int i = 0, j = n, mid = 0;
while (i < j) {
mid = (i + j) / 2;
if (arr[mid] == target)
return mid;
/* If target is less than array element,
then search in left */
if (target < arr[mid]) {
// If target is greater than previous
// to mid, return closest of two
if (mid > 0 && target > arr[mid - 1])
{
return getClosest(arr[mid - 1],arr[mid], target, mid-1,mid);
}
/* Repeat for left half */
j = mid;
}
// If target is greater than mid
else {
if (mid < n - 1 && target < arr[mid + 1])
return getClosest(arr[mid], arr[mid + 1], target, mid,mid+1);
// update i
i = mid + 1;
}
}
// Only single element left after search
return mid;
}
Link to Problem:- https://www.spoj.com/problems/GSS1
I am using Segment tree.
Node Information:-
maxSum --> maximum sum of the segment represented by node.
Sum ---> Total Sum of segment. (Although i think it's not needed)
maxPrefixSum ---> maximum prefix sum possible in segment. i.e starting from first element of segment.
maxSuffixSum ---> same as maxPrefixSum but starting from last element of segment.
Calculation of Node Values:-
("res" is new node, "left" and "right" are its left and right childs respectively)
res.Sum = left.Sum + right.Sum;
res.maxSum = max(max(left.maxSum, right.maxSum), left.maxSuffixSum + right.maxPrefixSum);
res.maxSuffixSum = max(left.maxSuffixSum + right.Sum, right.maxSuffixSum);
res.maxPrefixSum = max(left.maxPrefixSum, left.Sum + right.maxPrefixSum);
CODE
#include<bits/stdc++.h>
using namespace std;
#define int long long int
class node
{
public:
int Sum, maxSuffixSum, maxPrefixSum, maxSum;
node()
{
Sum = maxSuffixSum = maxPrefixSum = maxSum = 0;
}
};
node node_value(node left, node right)
{
node res;
res.Sum = left.Sum + right.Sum;
res.maxSum = max(max(left.maxSum, right.maxSum), left.maxSuffixSum + right.maxPrefixSum);
res.maxSuffixSum = max(left.maxSuffixSum + right.Sum, right.maxSuffixSum);
res.maxPrefixSum = max(left.maxPrefixSum, left.Sum + right.maxPrefixSum);
return res;
}
void makeSegmentTree(vector<int> arr, vector<node> &tree, int idx, int start, int finish)
{
if(finish == start)
{
tree[idx].Sum = tree[idx].maxPrefixSum = tree[idx].maxSuffixSum = tree[idx].maxSum = arr[start];
return;
}
int mid = start + (finish - start)/2;
makeSegmentTree(arr, tree, 2*idx, start, mid);
makeSegmentTree(arr, tree, 2*idx+1, mid+1, finish);
tree[idx] = node_value(tree[2*idx], tree[2*idx + 1]);
}
node queryTree(vector<node> &tree, int idx, int start, int finish, int left, int right)
{
if(start >= left && finish <= right)
{
return tree[idx];
}
else
{
int mid = start + (finish - start)/2;
if(start <= left && right <= mid)
{
return queryTree(tree, 2*idx, start, mid, left, right);
}
else if(left > mid && right <= finish)
{
return queryTree(tree, 2*idx+1, mid+1, finish, left, right);
}
else
{
node ans1 = queryTree(tree, 2*idx, start, mid, left, mid);
node ans2 = queryTree(tree, 2*idx+1, mid+1, finish, mid+1, right);
return node_value(ans1, ans2);
}
}
}
int32_t main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
vector<int> arr(n+1, 0);
for(int i=1;i<n+1;i++)
{
cin>>arr[i];
}
vector< node > tree(4*n);
makeSegmentTree(arr, tree, 1, 1, n);
int q;
cin>>q;
while(q--)
{
int x, y;
cin>>x>>y;
cout<<queryTree(tree, 1, 1, n, x, y).maxSum<<endl;
}
return 0;
}
Take quick sort as an example, both recursion and non-recursion methods are listed below.
I think both methods actually implement the same algorithm, as a stack is used to simulate the recursion process in non-recursion method.
However, I got AC with recursion method but Time Limit Exceeded with non-recursion method after 85% test cases passed.
So, any problem with my non-recursion method or there is a time complexity difference between two methods?
THX!
// non-recursion
void sortIntegers(vector<int> &A) {
if (A.empty()) {
return;
}
stack<pair<int, int>> ranges;
ranges.push(pair<int, int>(0, A.size() - 1));
while (!ranges.empty()) {
pair<int, int> r = ranges.top();
ranges.pop();
int mid = A[r.second],
left = r.first,
right = r.second - 1;
if (r.first >= r.second) {
continue;
}
while (left < right) {
while (A[left] < mid && left < right) {
left++;
}
while (A[right] >= mid && left < right) {
right--;
}
swap(A[left], A[right]);
}
if (A[left] < A[r.second]) {
left++;
} else {
swap(A[left], A[r.second]);
}
ranges.push(pair<int, int>(0, left - 1));
ranges.push(pair<int, int>(left + 1, r.second));
}
// recursion
void sortIntegers(vector<int> &A) {
quick(A, 0, A.size() - 1);
}
void quick(vector<int> & A, int start, int end) {
if (start >= end) {
return;
}
int mid = A[end], //5
left = start, // 0
right = end - 1; //3
while (left < right) {
while (A[left] < mid && left < right) {
left++;
}
while (A[right] >= mid && left < right) {
right--;
}
swap(A[left], A[right]);
}
if (A[left] >= A[end]) {
swap(A[left], A[end]);
}else {
left++;
}
quick(A, start, left - 1);
quick(A, left + 1, end);
}
At first glance, you have at the bottom of your loop:
ranges.push(pair<int, int>(0, left - 1));
ranges.push(pair<int, int>(left + 1, r.second));
To me that should be
ranges.push(pair<int, int>(r.first, left - 1));
ranges.push(pair<int, int>(left + 1, r.second));
I'm writing a recursive binary search function for a project in C++ and for some reason, it runs infinitely and does not execute properly. My code is as follows:
int recursiveBin(const int list[], int listLength, int searchItem)
{
if(listLength == 0)
return -1;
int mid = (listLength - 1)/2;
if(list[mid] > searchItem)
return recursiveBin(list, mid - 1, searchItem);
else if(list[mid] < searchItem)
return recursiveBin(list, mid + 1, searchItem);
else
return mid;
}
Can someone please help me with this? I'm not sure what is going wrong with my function and where the infinite loop comes.
Add one more parameter to store the search boundary.
int recursiveBin(const int list[], int start, int end, int searchItem)
{
if(end > start)
return -1;
int mid = (start + end)/2;
if(list[mid] > searchItem)
return recursiveBin(list, start, mid - 1, searchItem);
else if(list[mid] < searchItem)
return recursiveBin(list, mid + 1, end, searchItem);
else
return mid;
}
I was making binary search program to find the number of elements between the Left and Right values in a range .
I code it :
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> arr(20);
int search(int value,int low,int high)
{
if (high <= low)
return low;
int mid = (low + high) / 2;
if (arr[mid] > value)
return search(value,low,mid-1);
else
return search(value,mid+1,high);
}
int main(){
int n;
cin>>n;
//ENTER SORTED ARRAY
for(int i=0;i<n;i++){
cin>>arr[i];
}
int left;
cin>>left;
//RIGHT IS GREATER OR EQUAL TO LEFT
int right;
cin>>right;
cout<<search(right,0,n-1)-search(left,0,n-1)+1<<"\n";
}
It's giving right answer for some ranges.
But for some its giving wrong like If N=6 and array be [1 3 5 8 10 13] and say the range be [5,9] then it's giving 1 as the answer but it should be 2 as 5 and 8 both are in the range.
try this
int search(int value,int low,int high)
{
if (high <= low)
return low;
int mid = (low + high) / 2;
if(arr[mid]==value){ // add this line it would be work for you
return mid;
}
if (arr[mid] > value)
return search(value,low,mid-1);
else
return search(value,mid+1,high);
}
and make correction in main()
cout<<search(right,0,n-1)-search(left,0,n-1)<<"\n";
int search(int value,int low,int high)
{
if (high <= low + 1)
return low;
int mid = (low + high) / 2;
if (arr[mid] > value)
return search(value,low,mid);
else
return search(value,mid,high);
}
And in your main function
cout<<search(right+1,0,n-1)-search(left,0,n-1)<<"\n";
One problem is that when arr[mid] == value, you just ignore it and recurse to the right.
You'll need to either include mid in your right range, or return mid if arr[mid] == value.
I also see duplicate values (if these are possible) being a problem - when recursing to find the left-most position, you need to find the first duplicate value, when recursing to find the right-most position, you need to find the last duplicate value, so a single function without a flag to indicate which one we're doing isn't going to work. To illustrate the problem:
If the range is [5,5] and the input is [1,2,5,5,5,6,8], the same recursive call finding the position of 5 will always return the position of the same 5, where-as you need to return index 2 for the left range and index 4 for the right, as to get 3 as your output.
There is no check that arr[mid] can be == value. In your example, first iteration for left == 5 gives mid == ( 0 + (6-1) )/2 = 5/2 = 2 and arr[2] is exactly 5. We should stop, but your code goes to the branch search(5, 3, 5);
The logic of your program seems wrong, if you want to find the number of elements in the arr that are in the range of [left,right], try this:
int i;
int count = 0;
for(i = 0; i < n; i++) {
if (arr[i] >= left && arr[i] <= right)
count++;
}
If you insist on using binary search try this :
static int search(int value,int low,int high)
{
if (high <= low)
return low;
int mid = (low + high) / 2;
if (arr[mid] == value)
return mid;
int idx;
if (arr[mid] > value)
idx = search(value,low,mid-1);
else
idx = search(value,mid+1,high);
if (value == arr[idx]) {
return idx;
}
else {
if(value > arr[idx])
return mid +1;
else
return mid;
}
}