Adjust the iterative binary search code so that it uses only two comparisons instead of three (in
the main while loop). *Note: The three comparisons are in the while loop, and two if statements
within the loop.
#include <stdio.h>
int ItBinarySearch(int arr[], int len, int target) {
int first = 0;
int last = len-1;
while (first <= last){
// Assert: array is sorted
int mid = (first+last) / 2;
if (target == arr[mid])
return 1;
if (target < arr[mid])
last = mid-1;
else first = mid+1;
}
return 0;
}
int main(void){
int arr[6]={0,1,2,3,4,5};
int len=sizeof(arr)/sizeof(arr[0]);
int target = 4;
printf("%d\n",ItBinarySearch(arr,len,target));
}
Hint: try moving one of the if/else statements outside the loop. Which if/else would be the most likely candidate where the algorithm would still work if it were outside the statement?
Related
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.
In the question we were told that the crux of the algorithm is the fact that
"When we get down to single elements, that single
element is returned as the majority of its (1-element) array. At every other level, it will get return values from its
two recursive calls. The key to this algorithm is the fact that if there is a majority element in the combined array,
then that element must be the majority element in either the left half of the array, or in the right half of the array."
My implementation was this, probably very buggy but the general idea was this:
#include <stdio.h>
int merge(int *input, int left, int middle, int right, int maj1, int maj2)
{
// determine length
int length1 = middle - left + 1;
int length2 = right - middle;
// create helper arrays
int left_subarray[length1];
int right_subarray[length2];
// fill helper arrays
int i;
for (i=0; i<length1; ++i)
{
left_subarray[i] = input[left + i];
}
for (i=0; i<length2; ++i)
{
right_subarray[i] = input[middle + 1 + i];
}
left_subarray[length1] = 100;
right_subarray[length2] = 100;
//both return majority element
int count1 = 0;
int count2 = 0;
for (int i = 0; i < length1; ++i) {
if (left_subarray[i] == maj1) {
count1++;
}
if (right_subarray[i] == maj1) {
count1++;
}
}
for (int i = 0; i < length2; ++i) {
if (right_subarray[i] == maj2) {
count2++;
}
if (left_subarray[i] == maj2) {
count2++;
}
}
if (count1 > ((length1+length2) - 2)/2){
return maj1;
}
else if (count2 > ((length1+length2) - 2)/2){
return maj2;
}
else
return 0;
}
int merge_sort(int *input, int start, int end, int maj1, int maj2)
{
//base case: when array split to one
if (start == end){
maj1 = start;
return maj1;
}
else
{
int middle = (start + end ) / 2;
maj1 = merge_sort(input, start, middle, maj1, maj2);
maj2 = merge_sort(input, middle+1, end, maj1, maj2);
merge(input, start, middle, end, maj1, maj2);
}
return 0;
}
int main(int argc, const char* argv[])
{
int num;
scanf("%i", &num);
int input[num];
for (int i = 0; i < num; i++){
scanf("%i", &input[i]);
}
int maj;
int maj1 = -1;
int maj2 = -1;
maj = merge_sort(&input[0], 0, num - 1, maj1, maj2);
printf("%d", maj);
return 0;
}
This obviously isn't divide and conquer. I was wondering what is the correct way to implement this, so I can have a better understanding of divide and conquer implementations. My main gripe was in how to merge the two sub-array to elevate it to the next level, but I am probably missing something fundamental on the other parts too.
Disclaimer: This WAS for an assignment, but I am analyzing it now to further my understanding.
The trick about this particular algorithm, and why it ends up O(n log n) time is that you still need to iterate over the array you are dividing in order to confirm the majority element. What the division provides is the correct candidates for this iteration.
For example:
[2,1,1,2,2,2,3,3,3,2,2]
|maj 3| maj 2
maj 2 | maj None
<-------------------> still need to iterate
This is implicit in the algorithm statement: "if there is a majority element in the combined array, then that element must be the majority element in either the left half of the array." That "if" indicates confirmation is still called for.
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;
}
Here I made a quicksort implementation that uses (at least tries to) a little trick that is possible because I know the input is a list of numbers in the set {1,2,...,1023}. In particular I am not using a pivot that is necessarily in the list itself. Here is the main part of the function
int partition2(int length, int arr[], int mask) {
int left = 0;
int right = length;
while (left < right) {
while ((left < right) && (!((arr[left])&mask)) ) {
left++;
}
while ((left < right) && ((arr[right-1])&mask)) {
right--;
}
if (left < right) {
right--;
swap(left, right, arr);
left++;
}
}
left--;
return left;
}
void qSort2(int length, int arr[], int mask) {
int boundary;
if (length <= 1) {
return; /* empty or singleton array: nothing to sort */
}
boundary = partition2(length, arr, mask);
qSort2(boundary, arr,mask/2);
qSort2(length - boundary - 1, &arr[boundary + 1], mask/2);
}
main(){
int length = 200;
int *arr;
arr = generateNumbers(length);
qSort2(length, arr, 512);
int i;d
for(i=0;i<length;i++){
printf("%d ", arr[i]);
}
}
Sorry for the lengthy code. The function generateNumbers just makes a vector of size length with numbers from the given range and swap simply swaps two elements from the array. Now I am trying to exploit the fact that all numbers are smaller that 1024. So roughly speaking half of them will contain a 1 in binary representation in the position corresponding to 2^9=512. So we can use that to split the list in two lists. Then we check for both list what the digit corresponding to 2^8 is and split the list again. I am using the variable mask for this and the operator n&mask is zero if the is smaller then mask and non zero if it is larger that mask. For some reason though, it does not seem to work. Does anyone have any idea why? The output list is almost sorted but there are just some mistakes at certain places. If anyone could help me out that would be great. Thanks!
Here is the generateNumbers function:
void *makeDynamicIntArray(int length) {
void *ptr = malloc(length*sizeof(int));
if (ptr == NULL) {
printf("\nMalloc failed: out of memory?\n");
exit(-1);
}
return ptr;
}
int *generateNumbers(int length) {
int i, *arr = makeDynamicIntArray(length);
for (i=0; i<length; i++) {
arr[i] = rand() % 1024;
}
return arr;
}
I have been trying to get this prototype for finding mode of an array to work but it is not returning the right thing, could someone please tell me what I am doing wrong.
int mode(int array[], int size)
{
int x;
int mode = 0;
int largest = 0;
for (x = 0; x < size; x++)
{
if (array[x] > largest)
{
largest = array[x];
mode = x;
}
}
return mode;
}
First of all if that's c++ Arrays are numbered from 0, so x should be 0 in the for. also x should be checked against < size. Other then that the code is good.
In the question you've mentioned that " prototype for finding mode of an array " ,but this program is intended to find the position of the largest number in an array, because
mode = x; // x is the value of i which in-turn is the position of element in the array
and the value of mode is returned. So the position of the largest element counting from the zero'th element's position is shown.
If you want a program to find the mode (element/number that occurs most often) in an array, here it is
#include <stdio.h>
int mode(int array[], int size);
int main()
{
int Num[100],size,ret_Val,i;
clrscr();
printf("Enter the size of the array\n");
scanf("%d",&size);
printf("%d ",size);
for(i=0;i<size;i++)
{
scanf("%d",&Num[i]);
}
ret_Val=mode(Num,size);
printf("Mode of the array is %d",ret_Val);
getch();
return 0;
}
int mode(int array[], int size)
{
int cntMde = 1;
int i;
int cnt = 1;
int num = array[0];
int mode = num;
for ( i=1; i<size; i++)
{
if (array[i] == num)
{
cnt++;
}
else
{
if (cnt > cntMde)
{
cntMde = cnt;
mode = num;
}
cnt = 1;
num = array[i];
}
}
return mode;
}
And the output is
Mode of the array is 44
I have analyzed four ways to calculate mode of the array:
If range of numbers in the array is small then use counting sort - O(N) time, (N) space but very efficient
Index elements in the array in hash table - O(N) time, O(N) space
Sort the array and then count successive equal elements - O(NlogN) time, O(1) space
Partially sort the array but skip partitions smaller than current candidate - O(NlogN) time, O(1) space but much more efficient than fully sorting the array because many partitions will be skipped
You can find source code for all four methods and performance comparison in this article: Finding Mode of an Array