There are lots of recursion questions and I basically understand some simple recursion algorithm such as sum of array elements. However, my friend gave me this code which reverses an array:
void r(int a[], int s)
{
if(s <=2 ) return;
int t = a[0];
a[0] = a[s-1];
a[s-1] = t;
r(&a[1], s-2); // this line confused me, why &a[1]
}
I know how to reverse an array using a normal for loop. But this code really confused me about recursion.
Can anyone explain the above line of code?
It is equvalent to
void r(int *arr, size_t len)
{
for ( ; len >= 2; arr+=1,len-=2 ) {
int t = arr[0];
arr[0] = arr[len-1];
arr[len-1] = t;
}
}
, where the recursive call is replaced by the loop. Ihe "increment" part of the loop (arr+=1,len-=2) is exactly the same as the parameters for the recursive call; the end condition (len >= 2) is equivalent to the recursion stopper (which was wrong in the original).
The idea behind this algorithm is at each step:
-: to swap the last a[s-1] and first a[0] elements of the array:
int t = a[0];
a[0] = a[s-1];
a[s-1] = t;
-: and to swap the middle recursively:
r(&a[1], s-2);
To understand the syntax, keep in mind that &a[n] is address of the n+1th element of the given array. If you have int *b = &a[1], then b[0] == a[1], b[1] == a[2], etc.
So:
&a[1] refers to an array starting at the second element of array a.
s - 2 means that the length of the array you pass recursively is shorter by 2 elements.
If you have an array [1 2 3 4 5 6 7 8 9 10], here's what happens as the recursion progresses:
[1 2 3 4 5 6 7 8 9 10] // r(&a[0], 10)
10 [2 3 4 5 6 7 8 9] 1 // r(&a[1], 8
10 9 [3 4 5 6 7 8] 2 1 // r(&(&a[1])[1], 6)
10 9 8 [4 5 6 7] 3 2 1 // r(&(&(&a[1])[1])[1], 4)
10 9 8 7 [5 6] 4 3 2 1 // r(&(&(&(&a[1])[1])[1])[1], 2)
Cool thing is that this analysis shows us that the terminating condtion s <= 2 is wrong: the innermost 2 elements in an even-sized array will never get swapped. It should be changed to s < 2.
Simplified Crazy walk trough;
void reverse(int a[], int s)
{
int temp; /* temporary value */
if (s <= 2) return; /* trigger done */
t = a[0]; /* temp = first index of a */
a[0] = a[s - 1]; /* a[0] = a[end - 1] (end including \0) */
a[s - 1] = t; /* a[end - 1] = temp */
r(&a[1], s - 2); /* pass address of a[1] and end - 2 */
}
Given the char array "ABCDEFG"
Simplified memory table could be:
Address Value
7 A
8 B
9 C
a D
b E
c F
d G
/* Or as used here: */
789abcd <- Simplified memory address
ABCDEFG
We get; main() calls reverse(ABCDEFG, 7)
List 1
Address ref. to A are pushed on to the stack (A{BCDEFG})
7 are pushed on to the stack
return address for caller is pushed onto the stack
etc.
function called
And something like
#::::::::::::::::::::::::::::::::::::::::::::::::::::
reverse(ABCDEFG, 7); # Push to STACK 0xB (As List 1)
#====================================================
789abcd <- Memory address.
ABCDEFG <- Values.
0123456 <- Indexes for a in recursion 1.
if (7 <= 2) return;
temp = A
+ .
a[0] = a[6] => ABCDEFG = GBCDEFG
+
a[6] = temp => GBCDEFG = GBCDEFA
reverse(BCDEFA, 5); # Push to STACK 0xC (As in List 1)
#====================================================
7 89abcd <- Memory addresses.
[G]BCDEFA <- Values
012345 <- Indexes for a in recursion 2.
if (5 <= 2) return;
temp = B
+ .
a[0] = a[4] => BCDEFA = FCDEFA
+
a[4] = temp => FCDEFA = FCDEBA
reverse(CDEBA, 3); # Push to STACK 0xD (As in List 1)
#====================================================
78 9abcd <- Memory addresses.
[GF]CDEBA <- Values.
01234 <- indexes for a in recursion 3.
if (3 <= 2) return;
temp = C
+ .
a[0] = a[2] => CDEBA = EDEBA
+
a[2] = temp => EDEBA = EDCBA
reverse(DCBA, 1); # Push to STACK 0xE (As in List 1)
#====================================================
789 abcd <- Memory addresses.
[GFE]DCBA <- Values.
0123 <- Indexes for a in recursion 4.
if (1 <= 2) return; YES!
#:::: roll back stack ::::
Pop STACK 0xE
Pop STACK 0xD
Pop STACK 0xC
Pop STACK 0xB
We are back in main() and memory region 789abcd has
been altered from ABCDEFG to GFEDCBA.
The important thing to realize is that a is a pointer to the first element of the array, so a is the same as &a[0]. &a[1] is a pointer to the second element of the array. So if you call the function with &a[1] as its argument, it works on the subarray that starts with the second element.
&a[1] is equivalent to a + 1, i.e. a pointer to the second element of the array. The function call reverses the "middle" s-2 elements of the array.
The function has to be called with:
A pointer to the first element of the array. In C it can be referenced by using the name of the array.
The size of the array.
The first 'if' checks that the array has as least two elements. Next, what the function does is to exchange the position of the first and the last element of the array.
The recursive call changes the bounds at which the next step has to work. It increments the beginning of the array by one position, and also decreases the end of the array by one position; since these two elements have been reversed in this iteration.
Related
I have this algorithm. How can I do it faster than O(n^2) ?
Here is the algorithm :
We are given an array of size k in one operation we choose the smallest positive missing integer from the last k elements of the array and we add it to the end of the array.
for example if k = 4 and the array is 4 7 2 2
after one operation the array becomes 4 7 2 2 1
and after 2 operations it becomes 4 7 2 2 1 3 (the smallest positive missing integer between 7 2 2 1 is 3)
after k + 1 operations whats the final array ?
I can't explain more than provide the steps.
The code is straightforward.
first is the array, last is the array + size
auto first = array;
auto last = first + k;
std::sort(first, last);
unsigned seq = 1;
// merge
auto std::vector dest(k + k + 1);
auto d_i = dest.begin();
auto d_end = dest.end();
while (d_i != d_end){ // we should fill destination
if(*first <= seq){
*d_i++ = *first;
if(seq == *first) seq++;
}else{
*d_i++ = seq++;
}
}
You are given all subset sums of an array. You are then supposed to recover the original array from the subset sums provided.
Every element in the original array is guaranteed to be non-negative and less than 10^5. There are no more than 20 elements in the original array. The original array is also sorted. The input is guaranteed to be valid.
Example 1
If the subset sums provided are this:
0 1 5 6 6 7 11 12
We can quickly deduce that the size of the original array is 3 since there are 8 (2^3) subsets. The output (i.e original array) for the above input is this:
1 5 6
Example 2
Input:
0 1 1 2 8 9 9 10
Output:
1 1 8
What I Tried
Since all elements are guaranteed to be non-negative, the largest integer in the input must be the total of the array. However, I am not sure as to how do I proceed from there. By logic, I thought that the next (2^2 - 1) largest subset sums must include all except one element from the array.
However, the above logic does not work when the original array is this:
1 1 8
That's why I am stuck and am not sure on how to proceed on.
Say S is the subset sum array and A is the original array. I'm assuming S is sorted.
|A| = log2(|S|)
S[0] = 0
S[1] = A[0]
S[2] = A[1]
S[3] = EITHER A[2] OR A[0] + A[1].
In general, S[i] for i >= 3 is either an element of A or a combination of the elements of A that you've already encountered. When processing S, skip once per combination of known elements of A that generate a given number, add any remaining numbers to A. Stop when A gets to the right size.
E.g., if A=[1,2,7,8,9] then S will include [1,2,1+2=3,...,1+8=9, 2+7=9,9,...]. When processing S we skip over two 9s because of 1+8 and 2+7, then see a third 9 which we know must belong to A.
E.g., if S=[0,1,1,2,8,9,9,10] then we know A has 3 elements, that the first 2 elements of A are [1,1], when we get to 2 we skip it because 1+1=2, we append 8 and we're done because we have 3 elements.
Here's an easy algorithm that doesn't require finding which subset sums to a given number.
S ← input sequence
X ← empty sequence
While S has a non-zero element:
d ← second smallest element of S (the smallest one is always zero)
Insert d in X
N ← empty sequence
While S is not empty:
z ← smallest element of S
Remove both z and z+d from S (if S does not contain z+d, it's an error; remove only one instance of both z and z+d if there are several).
Insert z in N.
S ← N
Output X.
I revisited this question a few years later and finally managed to solve it! The approach that I've used to tackle this problem is the same as what Dave had devised earlier. Dave gave a pretty concrete explanation so I'll just add on some details and append my commented C++ code so that it's a bit more clear;
Excluding the empty set, the two smallest elements in S has to be the two smallest elements in A. This is because every element is guaranteed to be non-negative. Having known the values of A[0] and A[1], we have something tangible to work and build bottom-up with.
Following which, any new element in S can either be a summation of the previous elements we have confirmed to be in A or it can an entirely new element in A. (i.e S[3] = A[0] + A[1] or S[3] = A[2]) To keep track of this, we can use a frequency table such as an unordered_map<int, int> in C++. We then repeat this process for S[4], S[5]... to continue filling up A.
To prune our search space, we can stop the moment the size of A corresponds with the size of S. (i.e |A| = log(|S|)/log2). This help us drastically cut unnecessary computation and runtime.
#include <bits/stdc++.h>
using namespace std;
typedef vector<int> vi;
int main () {
int n; cin>>n;
vi S, A, sums;
unordered_map<int, int> freq;
for (int i=0;i<(int) pow(2.0, n);i++) {
int a; cin>>a;
S.push_back(a);
}
sort(S.begin(), S.end());
// edge cases
A.push_back(S[1]);
if (n == 1) {for (auto v : A) cout << v << "\n"; return 0;}
A.push_back(S[2]);
if (n == 2) {for (auto v : A) cout << v << "\n"; return 0;}
sums.push_back(0); sums.push_back(S[1]); sums.push_back(S[2]);
sums.push_back(S[1] + S[2]);
freq[S[1] + S[2]]++; // IMPT: we only need frequency of composite elements
for (int i=3; i < S.size(); i++) {
if (A.size() == n) break; // IMPT: prune the search space
// has to be a new element in A
if (freq[S[i]] == 0) {
// compute the new subset sums with the addition of a new element
vi newsums = sums;
for (int j=0;j<sums.size();j++) {
int y = sums[j] + S[i];
newsums.push_back(y);
if (j != 0) freq[y]++; // IMPT: coz we only need frequency of composite elements
}
// update A and subset sums
sums = newsums;
A.push_back(S[i]);
} else {
// has to be a summation of the previous elements in A
freq[S[i]]--;
}
}
for (auto v : A) cout << v << "\n";
}
Given an array of N < 10 000 elements, for each position i in the array, find (in the most efficient way) how many consecutive elements starting from it's left ( i.e from position i-1 to 0) are smaller or equal to array[i].
here's an example:
Array: 4 3 6 1 1 2 8 5 9
Res: 0 0 2 0 1 2 6 0 8
( pos 0 (element 4) -> 0 consecutive elements before it,
pos 1 (element 3) -> 0 consecutive elements before it smaller than 3 (4>3)
pos 2 (element 6) -> 2 consecutive elements before it smaller than 6 (4,3)
and so on..
)
I would assume it's a dynamic programming question since it says in the problem 'the most efficient way' and in the solution it says there's an O(n) solution.
The O(n^2) solution is straightforward, two loops, counting the elements.
Here's my thought about how the 0(n). One would assume:
for (int i = 1; i < array.Length; i++) {
if (array[i-1] > array[i])
{
c [i] = 0;
}
else {
c [i] = c [i - 1] + MAGIC_FORMULA;
}
}
Obviously, if I find an element greater than the next one, the result is clearly 0 (no numbers smaller than it on the left).
But what does the previous result tell me so I can use dynamic programming? I can't find any recurrence for that case. Also, that formula would have to be obtainable in O(1) for the whole solution to be O(n), right? Thought about using a hashset, but couldn't figure it out. Thought about using some modified version of kadane's algorithm, but no luck.
I'm dying to understand the O(n) solution. I've thought about the O(n) solution all day and I'm really stuck.
I'm not native so any help making this question better/more understandable would be really appreciated.
There is a linear solution, however it doesn't use dynamic programming, but rather a simple loop and a stack. First you can make the following observation: computing "the number of consecutive elements smaller or equal than c[i]" is almost the same task as finding "the greater index j <= i such that c[j] > c[i]".
The idea is as follows: for each i (sweeping from left i = 0 to right i = n - 1), we maintain the set of all indices j such that c[j] > c[k] for all j < k < i. This set can be stored in a stack, the lowest values at the top. When you read c[i], you pop elements until you get an index j such that c[j] > c[i]. This is the wanted index. Then you can push i on the stack.
Example: s is the stack. Here ans[i] will be max{j <= i | c[j] > c[i]}. ans[i] will be -1 if the previous set is empty.
i 0 1 2 3 4 5 6 7 8
c[i] 4 3 6 1 1 2 8 5 9
------------------------
i = 0:
- s = []: ans[0] = -1
- push i: s = [0]
i = 1:
- s = [0]: c[1] < c[0] -> ans[1] = 1
- push i: s = [0, 1]
i = 2:
- s = [0, 1]: c[2] >= c[1] -> pop
s = [0]: c[2] >= c[0] -> pop
s = []: ans[2] = -1
- push i: s = [2]
i = 3:
- s = [2]: c[3] < c[2] -> ans[3] = 2
- push i: s = [2, 3]
i = 4:
- s = [2, 3]: c[4] >= c[3] -> pop
s = [2]: c[4] < c[2] -> ans[4] = 2
- push i: s = [2, 4]
i = 5
- s = [2, 4]: c[5] >= c[3] -> pop
s = [2]: c[5] < c[2] -> ans[5] = 2
- push i: s = [2, 5]
i = 6
- s = [2, 5]: c[6] >= c[5] -> pop
s = [2]: c[6] >= c[2] -> pop
s = [] -> ans[6] = -1
- push i: s = [6]
i = 7
- s = [6]: c[7] < c[6] -> ans[7] = 6
- push i: s = [6, 7]
i = 8
- s = [6, 7]: c[8] >= c[7] -> pop
s = [6]: c[8] >= c[6] -> pop
s = [] -> ans[8] = -1
- push i: s = [8]
So, apparently, after 5 years since when the original question was posted, I found this problem while preparing for my Algorithms class. This is, to this day, the only solution I've found on the internet. It took me quite a bit of time to code the solution, so I am posting it here. Somebody might need it later. My code is written in Python3 and is refactored to the best of my abilities.
from collections import deque
def less_then_count(arr):
stack = deque()
ans = [0] * len(arr)
for i in range(len(arr)):
while len(stack)>0 and arr[i] >= arr[stack[-1]]:
stack.pop()
ans[i] = i
if len(stack) > 0:
ans[i] -= stack[-1]+1
stack.append(i)
return ans
print(*less_then_count([1,2,4,2,5]))
print(*less_then_count([4, 3, 6, 1, 1, 2, 8, 5, 9]))
(Editors/moderators please read my last comment on the selected answer to the question, before deleting this one.)
Stack operations
In our first example of aggregate analysis, we analyze stacks that have been aug- mented with a new operation. Section 10.1 presented the two fundamental stack operations, each of which takes O(1) time:
PUSH(S, x) pushes object x onto stack S.
POP(S) pops the top of stack S and returns the popped object.
Since each of these operations runs in O(1) time, let us consider the cost of each to be 1. The total cost of a sequence of n PUSH and POP operations is therefore n, and the actual running time for n operations is therefore (n).
Now we add the stack operation MULTIPOP(S,k), which removes the k top objects of stack S, or pops the entire stack if it contains fewer than k objects. In the following pseudocode, the operation STACK-EMPTY returns TRUE if there are no objects currently on the stack, and FALSE otherwise.
What is the running time of MULTIPOP(S, k) on a stack of s objects? The actual running time is linear in the number of POP operations actually executed, and thus it suffices to analyze MULTIPOP in terms of the abstract costs of 1 each for PUSH and POP. The number of iterations of the while loop is the number min(s,k) of objects popped off the stack. For each iteration of the loop, one call is made to POP in line 2. Thus, the total cost of MULTIPOP is min(s, k), and the actual running time is a linear function of this cost.
Let us analyze a sequence of n PUSH, POP, and MULTIPOP operations on an ini- tially empty stack. The worst-case cost of a MULTIPOP operation in the sequence is O(n), since the stack size is at most n. The worst-case time of any stack opera- tion is therefore O(n), and hence a sequence of n operations costs O(n2), since we may have O(n) MULTIPOP operations costing O(n) each. Although this analysis is correct, the O(n2) result, obtained by considering the worst-case cost of each operation individually, is not tight.
Using aggregate analysis, we can obtain a better upper bound that considers the entire sequence of n operations. In fact, although a single MULTIPOP operation can be expensive, any sequence of n PUSH, POP, and MULTIPOP operations on an initially empty stack can cost at most O(n). Why? Each object can be popped at most once for each time it is pushed. Therefore, the number of times that POP can be called on a nonempty stack, including calls within MULTIPOP, is at most the number of PUSH operations, which is at most n. For any value of n, any sequence of n PUSH, POP, and MULTIPOP operations takes a total of O(n) time. The average cost of an operation is O(n)/n = O(1). In aggregate analysis, we assign the amortized cost of each operation to be the average cost. In this example, therefore, all three stack operations have an amortized cost of O(1).
i want to print the value which contain in the multidimensional array.I know that if we write something like arr[3][4] then arr[0] is the pointer to the first element in the that multidimensional array.
I want to ask why this code give me garbage value after the program print the number containing in the multidimensional array?
this is the code:
#include <stdio.h>
#define ROW 3
#define COLL 4
int main(void) {
int arr[ROW][COLL]={{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
int *ptr;
for(ptr=arr[0];ptr<arr[ROW]+COLL;ptr++){
printf("%d ",*ptr);
}
printf("\n");
return 0;
}
this is the result when i compile the above code:
1 2 3 4 5 6 7 8 9 10 11 12 -1079481492 134513936 0 -1079481352
but after changing the for loop to the following:
for(ptr=arr[0];ptr<=arr[ROW-1]+COLL-1;ptr++)
the code work and give the exact number which contain in the multidimensional array.
Because arr[ROW] is an out-of-bounds access. The last valid position in arr is arr[ROW-1]. Thus the first version of your code invokes undefined behaviour.
The pointer to the last element is
arr[ROW-1] + COLL - 1
So you loop should be
for (ptr = arr; ptr < arr[ROW-1] + COLL; ptr++) {
Elements of an array are indexed from 0 so the last element in your matrix is arr[ROW-1][COLL-1].
When your pointer reaches arr[2] + COLL there is no such element because the second coordinate of the last element in last row is [COLL-1].
Elements of an array are stored in 1D so arr[0] + 4 is acctualy arr[1][0].
When you increment ptr++ it tells the compiler to access the next memory location after the current. So, when ptr points to a[0] + 4 it works because the compiler access the fifth value after a[0][0] which is actually the first value in the next row, arr[1][0], because their memory locations are next to each other.
When your ptr points to arr[4] + i, i = 0, 1, 2, 3 you get bad output because those elements are not in your array.
Because your first element, 1, is at arr[0]+0,
5 is at arr[1]+0,
9 is at arr[2]+0,
10 is at arr[2]+1,
11 is at arr[2]+2,
and 12, which is the last element of your array is at arr[2]+3.
but your for loop keeps moving even after the array ends, that is, until the memory location arr[3]+4 is reached. Giving you four garbage values because we have stored nothing in the memory after arr[2]+3.
so the for loop should be like:
for (ptr=arr; ptr <= arr[ROW-1]+COLL-1; ptr++);
which is equivalent to:
for (ptr=arr[0]; ptr <= arr[ROW-1]+COLL-1; ptr++);
as arr[0] and arr point to the same location in memory.
NOTE- try reading how memory is allocated in arrays of multiple dimensions.
Hope my question is clear and relavent, new to Pointers... - Can I copy a whole portion of an array at once, by refering to the pointer to the location of the first slot in the array I want to begin copying from?
For example -
Given an array : A [ 1,2,3,4,5,7,8,3,2,5,1,0,9]
- I want to copy only the part of the array from the n'th slot on, into the beginning of the array B [0 0 0 ..... ] (B is of the same length of A).
Can I do it at once, using pointers instead of a loop? Something like - switching the pointer to the 1'st slot in B with the pointer to the n'th slot of A, and the n'th slot in B with the last one in A?
Thanks a lot on advance!
That's what memcpy is for.
memcpy(B, A + n, (N - n) * sizeof(A[0]));
where N is the number of elements in A. If A is really an array (not just a pointer to one), then N can be computed as sizeof(A) / sizeof(A[0]), so the call simplifies to
memcpy(B, A + n, sizeof(A) - n * sizeof(A[0]));
memcpy lives in <string.h>; its first argument is the destination of the copy, its second the source.
(I'm sorry, I don't really follow what kind of pointer trick you have in mind, so I can't comment on that.)
I think I understand what you're asking. You can use pointers to set up your second array, but here is the problem with doing it that way:
int [] primary = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int * secondary = primary + 5;
At this point, primary is { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }, and secondary is { 6, 7, 8, 9, 0 }, but the problem is they both point to the same array in memory. So instead of having two independent copies, if you edit any of the elements of 'secondary', they are edited in 'primary' also.
secondary[2] = 10;
for(int i = 0; i < 10; ++i)
cout << primary[i] << ' ';
This portion of code would now yield:
1 2 3 4 5 6 7 10 9 0
The correct way to do it would to either be setting up the new array, and looping through copying over the values, or using memcpy().
Edit:
//Rotate an array such that the index value is moved to the front of the array
null rotateArray( &int original[], int size, int index)
{
int * secondary = new int[size]; //dynamically allocated array
for(int i = 0; i < size; ++i)
{
secondary[i] = original[(i+index)%size];
}
original = secondary; //Move the original array's pointer to the new memory location
}
Some notes:
secondary[i] = original[(i+index)%size];
this is how I rotated the array. Say you had an original array of size 5, and you wanted the fourth element to be the new start (remember, elements are numbered 0-(size-1)):
i = 0;
secondary[0] = original[(0 + 3)%5]// = original[3]
i = 1;
secondary[1] = original[(1 + 3)%5]// = original[4]
i = 2;
secondary[2] = original[(2 + 3)%5]// = original[0]
...
The last part of the code:
original = secondary;
is a little bit questionable, as I don't remember whether or not c++ will try and clean up the used memory once the function is exited. A safer and 100% sure way to do it would be to loop through and copy the secondary array's elements into the original array:
for(int i = 0; i < size; ++i)
original[i] = secondary[i];