finding negative number closest to 0 in array (log n complexity) - c

I have a question: write a function that gets an ascending array of whole numbers and their size.
It is given that the array contains at least one negative number and one positive number, and I need to find the closest negative number to the number 0.
for example: [-30,-25,-18,-10,11,11,20,30]
the function will return -10.
The problem is that I need to do it in O(log n) complexity and I don't know how to do this.
I made it only with O(n).
`
int f(int* arr, int size)
{
int i;
int result = arr[0];
for (i = 1;i < size;i++)
{
if (arr[i] < 0 && result < arr[i])
result = arr[i];
else
return result;
}
return result;
}

Here is a simple C implementation of a binary search, which works in O(log n) time.
#include <stdio.h>
int find(int *arr, size_t size)
{
size_t bot = 0;
size_t top = size; // it will never be top
size_t dif;
while((dif = top - bot) > 1) {
size_t mid = bot + dif / 2;
if(arr[mid] >= 0) { // eliminate non-negatives
top = mid;
}
else {
bot = mid;
}
}
return arr[bot];
}
int main(void) {
int arr[] = { -30, -25, -18, -10, 11, 11, 20, 30 };
size_t size = sizeof arr / sizeof arr[0]; //parentheses only needed for types
printf("%d\n", find(arr, size));
}
I like to use a binary search so that the top element is never a candidate.
Program output:
-10

Here's a possible way
int f( int *n, int size )
{
int low = 0, mid, high = size-1;
while( (mid = (low+high)/2) && n[mid] * n[mid+1] > 0 ) n[mid] < 0 ? (low = mid) : (high = mid);
return n[mid] ? n[mid] : n[mid-1];
}
I posted it condensed to give you something to do. Rewrite it properly using if else and do while.
The program uses min, max and mid as indexes for the array n[].
min is set to 0 and will always be the index of a negative number, max is set to size-1 and will always be the index of a positive number or of a 0. mid will always be between them (or exactly them).
The loop breaks when find an element (that is n[mid]) such that multiplied for the next one gives a negative number or zero.
Then the function returns n[mid], unless it is 0, in this case it returns the element before n[mid].
Note that if the array can contain dupes, then you need to handle the case of multiple 0s adding something like that at the end
while( !n[mid] ) --mid;
EDIT: I forgot to tell you that since the algorithm for the function is a binary search, it suits your time complexity requirements.

Related

Recursive function to find the number of continuous sub-sequences in an array having a sum in the given range

I wrote this code. The idea is to split the array into 2 parts and find the number of sub-sequences that satisfy the given condition. Now there can also be a sub-sequence with elements from both subarrays. Hence I wrote the crossub function.
The subarray function is going on an infinite loop (It's continuously printing the debug statement "BBBBBBBB"). I spent some time on this, but I guess I need some help.
Note : New to programming. I know the code is a piece of shit. But I am getting better.
#include <stdio.h>
#include <stdlib.h>
void crossub(int * A,int mid, int start, int end, int lbound, int ubound, int **k)
{
int leftsum = A[mid];
int crossum;
int rightsum = 0;
int i;int j;
for(i = mid -1; i>=0; i--)
{
leftsum = leftsum + A[i];
for(j = mid +1; j <=end; j++)
{
rightsum = rightsum + A[j];
crossum = rightsum + leftsum;
if (lbound <= crossum && crossum <= ubound) k++;
else if(crossum > ubound) break;
}
}
return;
}
void subarray(int * A, int start, int end, int lbound, int ubound, int *count)
{
printf("BBBBBBBBB ");
if(start == end)
{
if(lbound <= A[start] && A[start] <= ubound)
{
count++;
}
return;
}
int **k; int mid;
k = &count;
while (start <= end)
{
mid = (start + end)/2;
subarray(A, start, mid,lbound,ubound,count);
subarray(A, mid +1, end,lbound,ubound,count);
crossub(A, mid, start, end, lbound,ubound,k);
}
return;
}
int numRange(int* A, int n, int lbound, int ubound)
{
// printf("AAAAAAAAAAA");
int p = 0;
int *count;
count = &p;
subarray(A, 0, n-1,lbound,ubound, count);
return p;
}
int main()
{
int A[] = {30, 5,1,0,2, 15,20,25};
int n = sizeof(A)/sizeof(A[0]);
printf("%d", n);
int lbound = 6; int ubound = 8;
int k = numRange(A, n,lbound, ubound);
printf("%d ", k);
return 0;
}
I'm not sure that recursion is relevant here. The way here is to always have a range and check its sum. Initial range should contain the single first item (range can be defined via start and end indexes), initial value for sum should be equal to value of . Further processing is:
If your sum is less than you're looking for, expand range incrementing its end index and adding value of new item to current value of range's sum;
If your sum is greater than you're looking for, reduce range incrementing its start index and substracting value of excluded item from range's sum;
If your sum is OK for you, return it.
Dealing with ranges:
If your sum is less than you're looking for, and you're unable to increment its end index because it points to the last item in array you're looking through, you may return a result that says no range is satisfying your requirements;
If your sum is greater than you're looking for, and you're unable to increment its start index because it points to the last item in array, you may also return same "no answer" result.
I'm sure there is no efficient way of dealing with ranges using "divide and conquer" strategy.
Regarding your infinite loop, the issue is in the subarray function, namely:
while (start <= end)
{
mid = (start + end)/2;
subarray(A, start, mid,lbound,ubound,count);
subarray(A, mid +1, end,lbound,ubound,count);
crossub(A, mid, start, end, lbound,ubound,k);
}
As you can see, this is going to keep going forever, because you never change the values of start/end, so you keep calling subarray on the same section.
Although, as already stated by the first answer, this might not be the best way, but you can remove the while loop and see if it works, even if it might not be the best solution.

Efficient way to search an element

Recently I had an interview, where they asked me a "searching" question.
The question was:
Assume there is an array of (positive) integers, of which each element is either +1 or -1 compared to its adjacent elements.
Example:
array = [4,5,6,5,4,3,2,3,4,5,6,7,8];
Now search for 7 and return its position.
I gave this answer:
Store the values in a temporary array, sort them, and then apply binary search.
If the element is found, return its position in the temporary array.
(If the number is occurring twice then return its first occurrence)
But, they didn't seem to be satisfied with this answer.
What is the right answer?
You can do a linear search with steps that are often greater than 1. The crucial observation is that if e.g. array[i] == 4 and 7 hasn't yet appeared then the next candidate for 7 is at index i+3. Use a while loop which repeatedly goes directly to the next viable candidate.
Here is an implementation, slightly generalized. It finds the first occurrence of k in the array (subject to the +=1 restriction) or -1 if it doesn't occur:
#include <stdio.h>
#include <stdlib.h>
int first_occurence(int k, int array[], int n);
int main(void){
int a[] = {4,3,2,3,2,3,4,5,4,5,6,7,8,7,8};
printf("7 first occurs at index %d\n",first_occurence(7,a,15));
printf("but 9 first \"occurs\" at index %d\n",first_occurence(9,a,15));
return 0;
}
int first_occurence(int k, int array[], int n){
int i = 0;
while(i < n){
if(array[i] == k) return i;
i += abs(k-array[i]);
}
return -1;
}
output:
7 first occurs at index 11
but 9 first "occurs" at index -1
Your approach is too complicated. You don't need to examine every array element. The first value is 4, so 7 is at least 7-4 elements away, and you can skip those.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int array[] = {4,5,6,5,4,3,2,3,4,5,6,7,8};
int len = sizeof array / sizeof array[0];
int i = 0;
int steps = 0;
while (i < len && array[i] != 7) {
i += abs(7 - array[i]);
steps++;
}
printf("Steps %d, index %d\n", steps, i);
return 0;
}
Program output:
Steps 4, index 11
Edit: improved after comments from #Martin Zabel.
A variation of the conventional linear search could be a good way to go. Let us pick an element say array[i] = 2. Now, array[i + 1] will either be 1 or 3 (odd), array[i + 2] will be (positive integers only) 2 or 4 (even number).
On continuing like this, a pattern is observable - array[i + 2*n] will hold even numbers and so all these indices can be ignored.
Also, we can see that
array[i + 3] = 1 or 3 or 5
array[i + 5] = 1 or 3 or 5 or 7
so, index i + 5 should be checked next and a while loop can be used to determine the next index to check, depending on the value found at index i + 5.
While, this has complexity O(n) (linear time in terms of asymptotic complexity), it is better than a normal linear search in practical terms as all the indices are not visited.
Obviously, all this will be reversed if array[i] (our starting point) was odd.
The approach presented by John Coleman is what the interviewer was hoping for, in all probability.
If you are willing to go quite a bit more complicated, you can increase expected skip length:
Call the target value k. Start with the first element's value v at position p and call the difference k-v dv with absolute value av. To speed negative searches, have a peek at the last element as the other value u at position o: if dv×du is negative, k is present (if any occurrence of k is acceptable, you may narrow down the index range here the way binary search does). If av+au is greater than the length of the array, k is absent. (If dv×du is zero, v or u equals k.)
Omitting index validity: Probe the ("next") position where the sequence might return to v with k in the middle: o = p + 2*av.
If dv×du is negative, find k (recursively?) from p+av to o-au;
if it is zero, u equals k at o.
If du equals dv and the value in the middle isn't k, or au exceeds av,
or you fail to find k from p+av to o-au,
let p=o; dv=du; av=au; and keep probing.
(For a full flash-back to '60ies texts, view with Courier. My "1st 2nd thought" was to use o = p + 2*av - 1, which precludes du equals dv.)
STEP 1
Start with the first element and check if it's 7. Let's say c is the index of the current position. So, initially, c = 0.
STEP 2
If it is 7, you found the index. It's c. If you've reached the end of the array, break out.
STEP 3
If it's not, then 7 must be atleast |array[c]-7| positions away because you can only add a unit per index. Therefore, Add |array[c]-7| to your current index, c, and go to STEP 2 again to check.
In the worst case, when there are alternate 1 and -1s, the time complexity may reach O(n), but average cases would be delivered quickly.
Here I am giving the implementation in java...
public static void main(String[] args)
{
int arr[]={4,5,6,5,4,3,2,3,4,5,6,7,8};
int pos=searchArray(arr,7);
if(pos==-1)
System.out.println("not found");
else
System.out.println("position="+pos);
}
public static int searchArray(int[] array,int value)
{
int i=0;
int strtValue=0;
int pos=-1;
while(i<array.length)
{
strtValue=array[i];
if(strtValue<value)
{
i+=value-strtValue;
}
else if (strtValue==value)
{
pos=i;
break;
}
else
{
i=i+(strtValue-value);
}
}
return pos;
}
Here is a divide-and-conquer style solution. At the expense of (much) more bookkeeping, we can skip more elements; rather than scanning left-to-right, test in the middle and skip in both directions.
#include <stdio.h>
#include <math.h>
int could_contain(int k, int left, int right, int width);
int find(int k, int array[], int lower, int upper);
int main(void){
int a[] = {4,3,2,3,2,3,4,5,4,5,6,7,8,7,8};
printf("7 first occurs at index %d\n",find(7,a,0,14));
printf("but 9 first \"occurs\" at index %d\n",find(9,a,0,14));
return 0;
}
int could_contain(int k, int left, int right, int width){
return (width >= 0) &&
(left <= k && k <= right) ||
(right <= k && k <= left) ||
(abs(k - left) + abs(k - right) < width);
}
int find(int k, int array[], int lower, int upper){
//printf("%d\t%d\n", lower, upper);
if( !could_contain(k, array[lower], array[upper], upper - lower )) return -1;
int mid = (upper + lower) / 2;
if(array[mid] == k) return mid;
lower = find(k, array, lower + abs(k - array[lower]), mid - abs(k - array[mid]));
if(lower >= 0 ) return lower;
upper = find(k, array, mid + abs(k - array[mid]), upper - abs(k - array[upper]));
if(upper >= 0 ) return upper;
return -1;
}
const findMeAnElementsFunkyArray = (arr, ele, i) => {
const elementAtCurrentIndex = arr[i];
const differenceBetweenEleAndEleAtIndex = Math.abs(
ele - elementAtCurrentIndex
);
const hop = i + differenceBetweenEleAndEleAtIndex;
if (i >= arr.length) {
return;
}
if (arr[i] === ele) {
return i;
}
const result = findMeAnElementsFunkyArray(arr, ele, hop);
return result;
};
const array = [4,5,6,5,4,3,2,3,4,5,6,7,8];
const answer = findMeAnElementsFunkyArray(array, 7, 0);
console.log(answer);
Wanted to include a recursive solution to the problem. Enjoy

Modify any element of the array

Given an array of integers , you can modify any of a number of arbitrary positive integer , and ultimately makes the entire array is strictly increasing and are positive integers , and asked at least need to change a few numbers
input: 5 1 2 2 3 4
output: 3
and there is what i have tried ,Each number in order to reduce more a ( first number minus one , then the second number minus two ,the third number minus three)
#include <stdio.h>
int Modify_the_array(int B[],int n);
int max(int a,int b);
int main(int argc,char *argv) {
int before_array[]={1,2,3,4,1,2,3,4,5};
int len=sizeof(before_array[0])/sizeof(before_array);
int b;
b=Modify_the_array(before_array,len);
printf("%d\n",b);
return 0;
}
int max(int a,int b){
return a>b?a:b;
}
int Modify_the_array(int B[],int len) {
int i,b=0,n=1;
int maxsofar,tmp,j;
for (i=0;i<len;i++){
B[i]=B[i]-n;
n++;
}
maxsofar=0;
tmp=0;
for(i=0;i<len;i++) {
for (j=i+1;j<len;j++) {
if (B[j]==B[i]&&B[i]>1) {
maxsofar=max(maxsofar,++tmp);
b=len-maxsofar;
}
}
}
return b;
}
somebody recommend there is another solution for this question,more efficently ,can anyone give me some advice,thank in advance
I came across the same problem recently. To make clear:
Problem Statement
You are given a sequence of integers a1,a2,a3.....an. You are free to replace any integer with any other positive integer. How many integers must be replaced to make the resulting sequence strictly increasing?
Input Format
The first line of the test case contains an integer N - the number of entries in the sequence.
The next line contains N space separated integers where the ith integer is ai.
Output Format
Output the minimal number of integers that should be replaced to make the sequence strictly increasing.
Given your input, len = 5, arr = [1 2 2 3 4], after minus index+1, get [0 0 -1 -1 -1].
Ignoring negative elements(these must be changed), compute Longest Increasing Subsequence(nondecreasing for this problem), which is a classic Dynamic Programming problem.
Denote the length of LIS = n(these elements will not be changed). So the final answer(the part doesn't belong to the increasing subsequence and the ignored negative part) is len-n(5-2=3).
We can compute LIS in O(nlogn) time with O(n) space.
int solve(vector<int> &arr) {
int len = arr.size();
for(int i = 0; i < len; i++) {
arr[i] -= i+1;
}
vector<int> lis(len,0);
int n = 0;
for(int i = 0; i < len; i++) {
if(arr[i] >= 0) {
int pos = binarysearchPos(lis,n,arr[i]);
lis[pos] = arr[i];
if(n == pos)
n++;
}
}
return len-n;
}
int binarysearchPos(vector<int> &arr, int n, int target) {
if(n == 0)
return 0;
if(arr[n-1] <= target)
return n;
int low = 0, high = n-1;
while(low < high) {
int mid = (low+high)/2;
if(arr[mid] > target) {
high = mid;
} else {
low = mid+1;
}
}
return low;
}

C - Recursion array checking

i would like to ask about the array recursion in C, Let say i have an array in float
float arr[] = {12.5, 5.5, 6.0, 18.0};
i want to count the number which is greater than 10, so the result should be 2. However, below is what i did
int cntArray(float arr[], int size)
{
int number = 0;
if((cntArray(&arr[1], size - 1))>=5)
number++;
return number;
}
int main()
{
float arr[] = {12.5, 5.5, 6.0, 18.0};
int result;
result = cntArray(arr, 4);
printf("The result is : %d", result);
}
But it returns 0 as result, any solutions for it? Thanks
Another example:
int cntArray(float arr[], int size) {
if (!size) return 0;
return (arr[0] > 10.0 ? 1 : 0) + cntArray(&arr[1], size - 1);
}
Edit #1 (in reply to comment):
This simply evaluate through a ternary operator (?:) if the first index of arr[] is greater than 10.0. If true, 1 will be the lvalue, otherwise will be 0. The lvalue of cntArray(&arr[1], size - 1) (which will process the next element on the array after decrementing size and if size is different than 0, which in this case will immediately return 0) will be added to the lvalue of the ternary operator. Applying this recurring logic, the aftermath will be the number of elements in the array that are greater than 10.0.
Your cntArray() function lacks a recursion base case, and also seems to hardcode the wrong value (5 instead of 10).
It should be something like:
int cntArray(const float *arr, size_t size)
{
if(size > 0)
{
/* Count the first element, then recurse. */
const int count = arr[0] >= 10.f;
return count + cntArray(arr + 1, size -1);
}
return 0;
}
Your logic is severely flawed: You don't actually check if a value in the array is larger than 10. you also always return number which will always be zero meaning the condition will always be false.
int cntArray(float arr[], int size){
int number = 0;
if((number = cntArray(&arr[1], size - 1))>=5)
number++;
return number;
}
You maybe want to change 5 to 10.
int cntArray(float arr[], int size) {
int number = 0;
if (size > 0) number = cntArray(&arr[1], size - 1);
if (arr[0] > 10) number += 1;
return number;
}
I'm not sure what does this portion of your code does.
if((cntArray(&arr[1], size - 1))>=5)
number++;
I would something like this instead:
int cntArray(float arr[], int index, int size){
if (index == size) return 0; // base case
int rest = cntArray(arr, index + 1, size); // how many elements are greater
// then 10 in rest of the array
if (arr[index] > 10)
return rest + 1;
else
return rest;
}
And call it in the main like this:
cntArray(arr, 0, 4);

In less-than-linear time, find the duplicate in a sorted array

Today, an interviewer asked me this question. My immediate response was that we could simply do a linear search, comparing the current element with the previous element in the array. He then asked me how the problem could be solved in less-than-linear time.
Assumptions
The array is sorted
There is only one duplicate
The array is only populated with numbers [0, n], where n is the length of the array.
Example array: [0,1,2,3,4,5,6,7,8,8,9]
I attempted to come up with a divide-and-conquer algorithm to solve this, but I'm not confident that it was the right answer. Does anyone have any ideas?
Can be done in O(log N) with a modified binary search:
Start in the middle of the array: If array[idx] < idx the duplicate is to the left, otherwise to the right. Rinse and repeat.
If no number is missing from the array, as in the example, it's doable in O(log n) with a binary search. If a[i] < i, the duplicate is before i, otherwise it's after i.
If there is one number absent and one duplicate, we still know that if a[i] < i the duplicate must be before i and if a[i] > i, the absent number must be before i and the duplicate after. However, if a[i] == i, we don't know if missing number and duplicate are both before i or both after i. I don't see a way for a sublinear algorithm in that case.
I attempted to come up with a divide-and-conquer algorithm to solve this, but I'm not confident that it was the right answer.
Sure, you could do a binary search.
If arr[i/2] >= i/2 then the duplicate is located in the upper half of the array, otherwise it is located in the lower half.
while (lower != upper)
mid = (lower + upper) / 2
if (arr[mid] >= mid)
lower = mid
else
upper = mid-1
Since the array between lower and upper is halved in each iteration, the algorithm runs in O(log n).
ideone.com demo in Java
Difference between sum of given array elements and sum of 0 to n-1 natural numbers gives you the duplicated element.
Sum of 0 to n-1 elements is (N * N-1)/2
example array is [0,1,2,3,4,5,6,7,8,8,9]
sum of 0 to 9 natural numbers is : 45
sum of given array elements : 53
53-45 = 8 Which is the duplicated element
#include <bits/stdc++.h>
using namespace std;
int find_only_repeating_element(int arr[] , int n){
int low = 0;
int high = n-1;
while(low <= high){
int mid = low + (high - low)/2;
if(arr[mid] == arr[mid + 1] || arr[mid] == arr[mid - 1]){
return arr[mid];
}
if(arr[mid] < mid + 1){
high = mid - 2;
}else{
low = mid + 1;
}
}
return -1;
}
int main(int argc, char const *argv[])
{
int n , *arr;
cin >> n;
arr = new int[n];
for(int i = 0 ; i < n ; i++){
cin >> arr[i];
}
cout << find_only_repeating_element(arr , n) << endl;
return 0;
}
How about that? (recursion style)
public static int DuplicateBinaryFind(int[] arr, int left, int right)
{
int dup =0;
if(left==right)
{
dup = left;
}
else
{
int middle = (left+right)\2;
if(arr[middle]<middle)
{
dup = DuplicateBinaryFind(arr,left, middle-1);
}
else
{
dup = DuplicateBinaryFind(arr, middle+1, right);
}
}
return dup;
}
The example array is a little bit different from your question. Since n is the length of array and there are one and only duplicate in array, the value of each element in array should be in [0,n-1].
If that is true, then this question is the same one with How to find a duplicate element in an array of shuffled consecutive integers?
The following code should find the duplicate in O(n) time and O(1) space.
public static int findOnlyDuplicateFromArray(int[] a, boolean startWithZero){
int xor = 0;
int offset = 1;
for(int i=0; i < a.length; i++){
if(startWithZero)
xor = xor ^ (a[i] + offset) ^ i;
else
xor = xor ^ a[i] ^ i;
}
if(startWithZero)
xor = xor - offset;
return xor;
}

Resources