I have this homework assignment:
Let Pi be the element of arr in index i. We say an index i is ‘well-placed’ if there exists an index j (j >= i) so that summing the elements in Pi Pi+1 … Pj yields the index i. In other words, an index is ‘well-placed’ if a sequence of elements beginning at that index yields the index when summed.
We define ‘well-placed length’ of a well-placed index to be j-i+1 – The length of the sequence that when summed shows that the index is well placed. It is possible an index is well-placed with more than a single sequence of elements. The ‘well-placed length’ in that case is the maximal length of the various sequences defining the index as ‘well-placed’.
The ‘maximal well-placed length’ is the maximum between the well-placement length of all well-placed indices in arr.
If no index in the array is well-placed, the maximal well-placed length is considered to be zero.
This is the code I wrote (that does not work):
int longestIndexHelper(int arr[], int i, int cur, int sum, int flag)
{
if((arr[i]==115)||(i<0))
return 0;
if((sum==0)&&(flag==0))
cur= i;
if((sum+arr[i]==cur)&&(arr[i]<=cur))
return longestIndexHelper(arr, i+1, i, sum+arr[i], 1)+1;
else return 0;
}
int longestIndex(int arr[], int length)
{
int l, h;
if(length<=0)
return 0;
l= longestIndexHelper(arr, length-1, 0, 0, 0);
h= longestIndexHelper(arr, length, 0, 0, 0);
if(h>=l)
return longestIndex(arr, length-1);
else
return longestIndex(arr, length-2);
}
I tried to understand why it doesn't return the maximal value, I assume that the IF and ELSE need to define something else to do... I'm allowed only to use these two functions.
thank you!
The problem seems to be that you need to implement two "loops" via recursion; one is a loop starting at a given index and summing the values as it goes, keeping track of the maximum well placed length for that starting index. The other is a loop trying each possible starting index. I see that your helper function does the former. It seems that you intend the called function to do the latter, but it has no mechanism to keep track of the maximum found so far or the index to check, separate from the length of the input array. To do that, you might want to create another helper function to recurse through all the possible starting indexes. Though I would approach this by expanding the existing helper function to do this also, something like:
int _helper( int arr[], int len, int start, int cur, int sum, int max )
{
if (start >= len) {
/* game over, thanks for playing */
return max;
} else if (cur >= len) {
/* try another starting index */
return _helper( arr, len, start + 1, start + 1, 0, max );
} else if ( sum + arr[cur] == start && max < cur - start + 1 ) {
/* found a longer well placed length */
return _helper( arr, len, start, cur + 1, sum + arr[cur], cur - start + 1 );
} else {
/* bzzzt. try a longer length at this starting index */
return _helper( arr, len, start, cur + 1, sum + arr[cur], max );
}
}
int max_well_placed_length( int arr[], int len )
{
return _helper( arr, len, 0, 0, 0, 0 );
}
#include <stdio.h>
int main(int argc, char **argv) {
int arr[100];
int len = 0;
if (argc > 100) return 1;
while (--argc) sscanf(*++argv, "%d", &arr[len++]);
printf("max well placed length: %d\n", max_well_placed_length(arr, len));
return 0;
}
Assume that your longestIndex function finds the 'maximal well-placed length' for a given length parameter. Then it drops it (h and l aren't stored or returned anywhere, are they?), and calls itself with a decreased length. So the function will always return the result of either longestIndex(arr, 0) or longestIndex(arr, -1) which will be always 0.
EDIT: and the longestIndexHelper function can return only 0 too.
Related
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.
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.
I'm trying to write a recursive function that receives an array and it's size and some other variables (of my choice). The function returns the length of the longest series possible of ascending integers in the array. The limitation is not using loops and not calling other functions or using pointers or other libraries.
This is the code I wrote, which unfortunately isn't working and I don't understand why!
length4 = max_set(arr4, size4, 1, 0, 1, 1, 0);
int max_set(int arr[], int size, int max, int index1, int index2, int
currentMax, int i) {
int path1, path2;
if (index1 == size)
return currentMax;
if (index2 == size){
if (currentMax < max)
currentMax = max;
index1 = i + 1;
index2 = index1 + 1;
max = 1;
}
if (arr[index2]> arr[index1]){
path1 = max_set(arr, size, max + 1, index1, index2 + 1, currentMax, i);
path2 = max_set(arr, size, max + 1, index1 + 1, index2 + 1, currentMax, i);
}
path1 = max_set(arr, size, max, index1, index2 + 1, currentMax, i);
path2 = max_set(arr, size, max, index1 + 1, index2 + 1, currentMax,i);
if (path1 > path2)
return path1;
else
return path2;
}
Thank you!
I found the original code more complicated than it needs to be for the task at hand, so rather than try and fix it, I just simplified it:
#include <stdio.h>
#include <stdlib.h>
/*
* Determine maximum ascending sequence length using length so far.
* #arr points to first element of array.
* #size is length of array.
* #pos is position of remaining entries in array.
* #maxval is the maximum value included the sequence so far (if len > 0).
* #len is sequence length so far.
*
* Returns maximum ascending sequence length.
*/
int max_set_recurse(int arr[], int size, int pos, int maxval, int len)
{
int path1, path2, newlen;
if (size <= pos) {
/* Nothing left, so return sequence length so far. */
return len;
}
/* Try skipping the first remaining entry. */
path1 = max_set_recurse(arr, size, pos + 1, maxval, len);
if (len && arr[pos] <= maxval) {
/* First remaining entry is no larger than maximum value. */
/* Try beginning sequence at first remaining entry. */
newlen = 0;
} else {
/* Try extending the sequence with first remaining entry. */
newlen = len + 1;
}
path2 = max_set_recurse(arr, size, pos + 1, arr[pos], newlen);
/* Return the longest ascending sequence length of the two we tried. */
return path2 > path1 ? path2 : path1;
}
/*
* Determine maximum ascending sequence length
* #arr points to entries.
* #size is number of entries.
*
* Returns maximum ascending sequence length.
*/
int max_set(int arr[], int size)
{
return max_set_recurse(arr, size, 0, 0, 0);
}
int main(int argc, char *argv[])
{
int arr[argc - 1];
int i;
for (i = 1; i < argc; i++) {
arr[i - 1] = atoi(argv[i]);
}
printf("Longest ascending sequence length = %d\n", max_set(arr, argc - 1));
return 0;
}
(EDITED to comply with "no pointers" rule as far as possible in C, i.e. no overt use of pointers, given that arrays are passed as pointers, and array indexing is actually pointer arithmetic and pointer dereferencing in disguise!)
The max_set_recurse function is called with the remaining portion of the array to be checked (from pos onwards), the maximum value in the partial maximum ascending sequence so far (if any), and the length of the partial maximum ascending sequence so far (possibly zero).
If the remaining portion of the array is empty (size <= pos), just return the length of the sequence so far.
Otherwise, we can determine two sequence lengths, one that excludes the first remaining entry in the array (arr[pos]), and one that includes it. The function will return the maximum of these two sequence lengths.
For the recursion path that excludes the first remaining entry in the array, the recursion call will skip the first remaining entry and pass through the previous maximum value and sequence length.
For the recursion path that includes the first remaining entry in the array, the recursion call will skip the first remaining entry, use the value of the first remaining entry as the maximum value, and set the sequence length as follows:
if the previous length is zero, or the first remaining entry is greater than the previous maximum value, use the previous sequence length plus one;
otherwise, use a sequence length of zero.
The demo program is called with a sequence of numbers on the command line. It will print the length of the longest ascending sequence that can be found by skipping or including each element.
Here are some example command lines and outputs. I have marked the input numbers that form part of the longest sequence in bold, although the program does not report which numbers are part of the longest ascending sequence:
./ascend 3 23 2 45 0 21 80
Longest ascending sequence length = 4
./ascend 10 3 5 23 2 45 0 21 80
Longest ascending sequence length = 5
./ascend 10 3 5 23 2 45 21 80 20 21 22 23
Longest ascending sequence length = 6
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);
i've been stuck for hours trying to figure how can i write a function that gets and array of integers, and finds the length of the longest ascending sub-series in the array using recursion and no loops at all. im only allowed to use another 1 recursive function
for example, for the following array: {45,1,21,3,3,6,53,9,18} the outpot should be 5, because the longest sub-series is {1,3,6,9,18}.
So, basicly, a function that gets an array and its size, and needs to print the length of the longest sub-series using no loops at all, no global/static types, and it may use another "help" recursive function and thats it.
this is pretty much all i came up with, and its a mess and not working well.
I'm trying to scan the array while at all time i know the current index im looking at, the index that is being compared to the current, and the originla index from which i started the current sub-series.
I tried to scan the array while knowing the indexes that should be compared but i got stuck, here's what i got, i would really appreciate any tips and advices.
thanks.
void max_set(int arr[], int size)
{
int bigSeries[2] = { 0 };
calcSeries(arr, bigSeries,0, 0, 1, size -1, 1);
printf("number of max parts going up %d \n", bigSeries[0]);
}
void calcSeries(int arr[], int bigSeries[],int originalCHeckedIndex, int checkedIndex, int currentIndex, int lastIndex, int ascending)
{
if ((checkedIndex == lastIndex) || (currentIndex > lastIndex))
{
if (ascending > bigSeries[0])
bigSeries[0] = ascending;
if (originalCHeckedIndex == lastIndex)
return;
else
{
calcSeries(arr, bigSeries, originalCHeckedIndex + 1, originalCHeckedIndex + 1, originalCHeckedIndex + 2, lastIndex, 0);
return;
}
}
if (arr[currentIndex] > arr[checkedIndex])
{
calcSeries(arr, bigSeries, originalCHeckedIndex, currentIndex, currentIndex + 1, lastIndex, ascending + 1);
}
else
{
if (arr[originalCHeckedIndex] < arr[currentIndex])
calcSeries(arr, bigSeries, currentIndex, currentIndex, currentIndex + 1, lastIndex,ascending);
calcSeries(arr, bigSeries, originalCHeckedIndex, checkedIndex, currentIndex + 1, lastIndex, ascending);
}
}
The algorithm has many similarities with the one of first answer, yet covering a few corner cases you might want to watch out. Instead of writing a lengthy comment, I chose to write a new answer instead.
Sanity Checks
Do some sanity checks on the array, as I did in function max_set().
Is an array supplied at all (check for NULL)?
Is the supplied array size at least positive (consider size_t)?
Allowed Values
Data type int allows positive and negative values. The algorithm should handle both. At least I didn't read from your post that they have to be positive. My code looks a bit nicer if you skip that part.
Recursion
The idea of this algorithm (and the one from first answer) is to recursively walk through the array, beginning at the first element, ending at last. So this already defines the start and end of recursion, as documented in source code.
To find the longest sub-series of numbers this way, there are always three possibilities:
The longest sub-series can be reached by skipping the number that is currently processed
The longest sub-series can be reached by adding the number that is currently processed
The currently processed number cannot fit in
A number can be added if it's larger than the largest previously added number; we look for an ascending series after all. The current number could be larger than others in the array that have to be processed, yet. So we have to take both possibilities into account: continuing recursive steps without it and with it -- as long as it fits criteria.
Possible oversight
Take into account that INT_MIN, the smallest possible int value on the machine, is a perfectly valid number in the array. I have added the variable seen, which just records if INT_MIN has been seen at least once in the array or not. On first encounter, seen flips from 0 to 1, not allowing any further INT_MIN values due to requirement of ascending sub-series. Your example shows this requirement with two occurences of number 3.
Tests
Try to find various test cases, and think out of the box at times. NULL for array, negative size, empty array. Next, add fancy values like negative numbers, INT_MIN. Or create ascending series, descending ones, interlacing. Numbers occuring multiple times ...
#include <sys/limits.h>
#include <stdio.h>
int
analyze(int arr[], int size, int min, int seen)
{
int sub_count = 0, count = 0;
/* end of recursion */
if (size == 0)
return 0;
/* recursion step, without and with current number */
sub_count = analyze(arr + 1, size - 1, min, seen);
if (arr[0] > min || (min == INT_MIN && arr[0] == INT_MIN && !seen))
count = 1 + analyze(arr + 1, size - 1, arr[0], arr[0] == INT_MIN);
/* return length of largest sub-series */
return sub_count > count ? sub_count : count;
}
void
max_set(int arr[], int size)
{
int seq = 0;
if (arr != NULL && size > 0) {
/* start of recursion */
seq = analyze(arr, size, INT_MIN, 0);
}
printf("max sequence is %d\n", seq);
}
int
main(void)
{
int arr[] = { 45, 1, 21, 3, 3, 6, 53, 9, 18 };
max_set(arr, sizeof(arr) / sizeof(*arr));
return (0);
}
#include <stdio.h>
int calcSeries(int arr[], int size, int value, int count){
int self, skip, rest;
if(0 == size)
return count;
skip = calcSeries(arr + 1, size-1, value, count);//case of skip the top(self)
if(value < *arr){
self = calcSeries(arr + 1, size-1, *arr, count+1);//case of include top
if(skip > self)
self = skip;
} else
self = skip;
rest = calcSeries(arr + 1, size-1, -1, 0);
return self > rest ? self : rest;
}
void max_set(int arr[], int size){
printf("number of max parts going up %d \n", calcSeries(arr, size, -1, 0));
}
int main(void){
int array[]={45,1,21,3,3,6,53,9,18};
max_set(array, sizeof(array)/sizeof(*array));
return 0;
}