Reversing an array by recursively splitting the array in C++ - c++

string recursion(int arr[], int arrSize) {
if(arrSize == 1){
return to_string(arr[0]);
}
string letterLeft, letterRight, letterFull;
//logic1: Normal Recursion
//letterFull = to_string(a[n-1]) + " " + recursion(a, n-1);
//logic2: D&C ------------------------------------------------------ <
letterLeft += recursion(arr, arrSize/2);
letterRight += recursion(arr + arrSize/2, arrSize-arrSize/2) + " ";
letterFull += letterRight + letterLeft;
return letterFull;
}
I recently used the 'logic2: D&C' for splitting an array recursively to reverse them (more like Divide and Conquer).
(i.e. if 2,5,4,1 is given as input, output should be 1,4,5,2).
It passed all test case like the example I just gave. Yet, I felt like I don't really understand the flow of recursion. I am here to get help from someone in explaining what happens in the 'logic2: D&C' step-by-step with an example flowchart & values if possible?
PS:
I took help from https://stackoverflow.com/a/40853237/18762063 to implement this 'logic2: D&C'.
Edits - Made little changes to argument list.

It is unclear why there are used objects of the type std::string. To reverse an array of objects of the type char there is no need to use the class sdt::string. This is just inefficient. The function can look the following way
void recursion( char arr[], size_t arrSize )
{
if ( not ( arrSize < 2 ) )
{
std::swap( arr[0], arr[arrSize-1] );
recursion( arr + 1, arrSize - 2 );
}
}

The point of divide and conquer algorithms is breaking your data down to smaller and smaller pieces while processing it.
If you want to reverse an array for example, than the following should happen:
The data is split into 2 equal parts and the order of these parts gets switched (so the back half becomes the front half, and the front half becomes the back half)
The 2 split parts are then also broken down to 2-2 equal parts, and get reversed.
And so on, until the splits are 1 length, so they can't be split any further, resulting in a fully reversed array.
Reading material on D and C algorithms

Related

Counting numbers a AND s = a

I am writing a program to meet the following specifications:
You have a list of integers, initially the list is empty.
You have to process Q operations of three kinds:
add s: Add integer s to your list, note that an integer can exist
more than one time in the list
del s: Delete one copy of integer s from the list, it's guaranteed
that at least one copy of s will exist in the list.
cnt s: Count how many integers a are there in the list such that a
AND s = a , where AND is bitwise AND operator
Additional constraints:
1 ≤ Q ≤ 200000
0 ≤ s < 2 ^ 16
I have two approaches but both time out, as the constraints are quite large.
I used the fact that a AND s = a if and only if s has all the set bits of a, and the other bits can be arbitrarily assigned. So we can iterate over all these numbers and increase their count by one.
For example, if we have the number 10: 1010
Then the numbers 1011,1111,1110 will be such that when anded with 1010, they will give 1010. So we increase the count of 10,11,14 and 15 by 1. And for delete we delete one from their respective counts.
Is there a faster method? Should I use a different data structure?
Let's consider two ways to solve it that are two slow, and then merge them into one solution, that will be guaranteed to finish in milliseconds.
Approach 1 (slow)
Allocate an array v of size 2^16. Every time you add an element, do the following:
void add(int s) {
for (int i = 0; i < (1 << 16); ++ i) if ((s & i) == 0) {
v[s | i] ++;
}
}
(to delete do the same, but decrement instead of incrementing)
Then to answer cnt s you just need to return the value of v[s]. To see why, note that v[s] is incremented exactly once for every number a that is added such that a & s == a (I will leave it is an exercise to figure out why this is the case).
Approach 2 (slow)
Allocate an array v of size 2^16. When you add an element s, just increment v[s]. To query the count, do the following:
int cnt(int s) {
int ret = 0;
for (int i = 0; i < (1 << 16); ++ i) if ((s | i) == s) {
ret += v[s & ~i];
}
return ret;
}
(x & ~y is a number that has all the bits that are set in x that are not set in y)
This is a more straightforward approach, and is very similar to what you do, but is written in a slightly different fashion. You will see why I wrote it this way when we combine the two approaches.
Both these approaches are too slow, because in which of them one operation is constant, and one is O(s), so in the worst case, when the entire input consists of the slow operations, we spend O(Q * s), which is prohibitively slow. Now let's merge the two approaches using meet-in-the-middle to get a faster solution.
Fast approach
We will merge the two approaches in the following way: add will work similarly to the first approach, but instead of considering every number a such that a & s == a, we will only consider numbers, that differ from s only in the lowest 8 bits:
void add(int s) {
for (int i = 0; i < (1 << 8); ++ i) if ((i & s) == 0) {
v[s | i] ++;
}
}
For delete do the same, but instead of incrementing elements, decrement them.
For counts we will do something similar to the second approach, but we will account for the fact that each v[a] is already accumulated for all combinations of the lowest 8 bits, so we only need to iterate over all the combinations of the higher 8 bits:
int cnt(int s) {
int ret = 0;
for (int i = 0; i < (1 << 8); ++ i) if ((s | (i << 8)) == s) {
ret += v[s & ~(i << 8)];
}
return ret;
}
Now both add and cnt work in O(sqrt(s)), so the entire approach is O(Q * sqrt(s)), which for your constraints should be milliseconds.
Pay extra attention to overflows -- you didn't provide the upper bound on s, if it is too high, you might want to replace ints with long longs.
One of the ways to solve it is to break list of queries in blocks of about sqrt(S) queries each. This is a standard approach, usually called sqrt-decomposition.
You have to store separately:
Array A[v]: how much times s is present.
Array R[v]: sum of A[i] for all i supersets of v (i.e. result of cnt(v)).
List W of all changes (add, del operations) within current block of queries.
Note: arrays A and R are valid only for all the changes from the fully processed block of queries. All the changes that happened within the currently processed block of queries are stored in W and are not yet applied to A and R.
Now we process queries block by block, for each block of queries we do:
For each query within block:
add(v): store increment for v into W list.
del(v): store decrement for v into W list.
cnt(v): return R[v] + X(W), where X(W) is total changed calculated by trivial processing of all the changes in the list W.
Apply all the changes from W to array A, clear list W.
Recalculate completely array R from array A.
Note that add and del take O(1) time, and cnt takes O(|W|) = O(sqrt(S)) time. So step 1 takes O(Q sqrt(S)) time in total.
Step 2 takes O(|W|) time, which totals in O(Q) time overall.
The most important part is step 3. We need to implement it in O(S). Given that there are Q / sqrt(S) blocks, this would total in O(Q sqrt(S)) time as wanted.
Unfortunately, recalculating array S can be done in only O(S log S) time. That would mean O(Q sqrt(S) log (S)) time. If we choose block size O(sqrt(S log S)), then overall time is O(Q sqrt(S log S)). No perfect, but interesting nonetheless =)
Given the data structure that you described in one of the comments, you could try the following algorithm (I am giving it in pseudo-code):
count-how-many-integers(integer s) {
sum = 0
for i starting from s and increasing by 1 until s*2 {
if (i AND s) == i {
sum = sum + a[i]
}
}
return sum
}
More sophisticated optimizations should be possible in the inner loop to reduce the number of times the test is performed.

Perfect shuffle and unshuffle, with no auxiliary array

Before any concrete question, please note that my goal is not to shuffle randomly the array, but to perform a perfect shuffle as the one a ideal dealer may do with a set of cards, that is, splitting the deck in half and performing one shuffle passage (interleaving a card from one half deck with one card from the other half). (This is actually one exercise from Algorithms in C third edition by Sedgewick: nbr 11.3 page 445)
So, i'm not interested in algorithms like Fisher-Yates shuffle etc.
Said that, my point is to avoid using any auxiliary array when performing the shuffle, the code I was able to deliver is the following:
template<typename T>
void two_way_shuffle(vector<T>& data,int l,int r)
{
int n=(r-l)+1;
int m=(r+l)/2;
if(n%2==0) ++m;
int s,p{l+1};
for(;p<=r;p+=2,m++)
{
s=data[m]; //Make space
//Shift the elements
for(int i{m};i>p;i--)
data[i]=data[i-1];
//Put the element in the final position
data[p]=s;
}
}
template<typename T>
void two_way_unshuffle(vector<T>& data,int l,int r)
{
int n=(r-l)+1;
if(n%2!=0){
--r;
--n;
}
int m=(r+l)/2;
int s,p{l+1},w{r-1};
for(;p<=w;p++,w--)
{
s=data[w];
for(int i{w};i>p;i--)
data[i]=data[i-1];
data[p]=s;
}
//Complete the operation
for(p=l+1,w=m;p<w;p++,w--)
swap(data[p],data[w]);
}
The basic idea beside the shuffling operation is to keep track of the position in the array 'p' where the next element should be inserted, then copying that element from the array data at position 'w' leaving one empty space, then shifting the array from left to right in order to move the empty space exactly to the position 'p', once that was done the code just move to data[p] the previously saved value 's'. Pretty simple.. And it looks to work properly (some shuffle examples)
FROM: 12345678
TO: 15263748
FROM: IS THIS WORKING CORRECTLY OR NOT?
TO: ICSO RTRHEICST LWYO ROKRI NNGO T?
FROM: SHUFFLING TEST
TO: SNHGU FTFELSIT
My very problem is in the unshuffle operation, I believe that the swap sequence in the last for loop can be avoided, but I'm not able to find a cleaver way to do that. The problem is that the main loop unshuffle performs a shift operation which eventually leave the elements of the first half of the array in the wrong order (thus, requiring the swap in the second for).
I'm almost sure there must be a clever way to do the job without such a code complication..
Do you have any suggestion on what may be improved in the unshuffle algorithm? Or any other suggestion on what I've done?
Thanks
I think your code keeps too many variables. When you shuffle the array, you are treating a range [lo, hi] of decreasing size, where you swap the rightmost entry hi with the block of elements to te left [lo, hi). You can express the algorithm just in terms of these two variables:
0 1 2 3 4 5
------- swap [1, 3) and [3]
0 3 1 2 4 5
---- swap [3, 4) and [4]
0 3 1 4 2 5
- [5, 5) is empty: break
This is the same for an odd number of elements, except that the empty range goes out of bound, which is okay, since we don't access it. The operations here are: shift block right, place old hi element at lo position, increase lo and hi with strides 2 and 1.
When you unshuffle, you must revert the steps: Start lo and hi at the last element for even-sized and one element beyond the array for odd-sized array. Then do all steps in reverse order: decrease lo and hi first, then shift the block left and place the old lo at hi position. Stop when lo reaches 1. (It will reach 1, because we've started at an odd index and we decrement by 2.)
You can test your algorithm by printing lo and hi as you go: They must be the same for shuffling and unshufling, only in reverse order.
So:
template<typename T>
void weave(std::vector<T>& data)
{
size_t lo = 1;
size_t hi = (data.size() + 1) / 2;
while (lo < hi) {
T m = data[hi];
for (size_t i = hi; i-- > lo; ) data[i + 1] = data[i];
data[lo] = m;
lo += 2;
hi++;
}
}
template<typename T>
void unweave(std::vector<T>& data)
{
size_t n = data.size();
size_t lo = n + n % 2 - 1;
size_t hi = lo;
while (hi--, lo-- && lo--) {
T m = data[lo];
for (size_t i = lo; i < hi; i++) data[i] = data[i + 1];
data[hi] = m;
}
}
I've removed the left and right indices, which makes the code less flexible, but hopefully clearer to read. You can put them back in and will only need them to calculate your initial values for lo and hi.
You can perform both these steps with a fixed number of swaps, at the cost of a non-linear index calculation step. But for practical applications the time cost of the swap usually drives the total time, so these algorithms approach O(N).
For perfect shuffling, see https://cs.stackexchange.com/a/105263/58310 (or https://cs.stackexchange.com/q/105604/58310 for an alternate explanation)
For unshuffling, a related algorithm is described here: https://stackoverflow.com/a/55112294/10396

I have n spaces, in each space, I can place a number 0 through m. Writing a program to output all possible results. Need help :)

The idea is, given an n number of spaces, empty fields, or what have you, I can place in either a number from 0 to m. So if I have two spaces and just 01 , the outcome would be:
(0 1)
(1 0)
(0 0)
(1 1)
if i had two spaces and three numbers (0 1 2) the outcome would be
(0 1)
(1 1)
(0 2)
(2 0)
(2 2)
(2 1)
and so on until I got all 9 (3^2) possible outcomes.
So i'm trying to write a program that will give me all possible outcomes if I have n spaces and can place in any number from 0 to m in any one of those spaces.
Originally I thought to use for loops but that was quickly shotdown when I realzed I'd have to make one for every number up through n, and that it wouldn't work for cases where n is bigger.
I had the idea to use a random number generator and generate a number from 0 to m but that won't guarantee I'll actually get all the possible outcomes.
I am stuck :(
Ideas?
Any help is much appreciated :)
Basically what you will need is a starting point, ending point, and a way to convert from each state to the next state. For example, a recursive function that is able to add one number to the smallest pace value that you need, and when it is larger than the maximum, to increment the next larger number and set the current one back to zero.
Take this for example:
#include <iostream>
#include <vector>
using namespace std;
// This is just a function to print out a vector.
template<typename T>
inline ostream &operator<< (ostream &os, const vector<T> &v) {
bool first = true;
os << "(";
for (int i = 0; i < v.size (); i++) {
if (first) first = false;
else os << " ";
os << v[i];
}
return os << ")";
}
bool addOne (vector<int> &nums, int pos, int maxNum) {
// If our position has moved off of bounds, so we're done
if (pos < 0)
return false;
// If we have reached the maximum number in one column, we will
// set it back to the base number and increment the next smallest number.
if (nums[pos] == maxNum) {
nums[pos] = 0;
return addOne (nums, pos-1, maxNum);
}
// Otherwise we simply increment this numbers.
else {
nums[pos]++;
return true;
}
}
int main () {
vector<int> nums;
int spaces = 3;
int numbers = 3;
// populate all spaces with 0
nums.resize (spaces, 0);
// Continue looping until the recursive addOne() function returns false (which means we
// have reached the end up all of the numbers)
do {
cout << nums << endl;
} while (addOne (nums, nums.size()-1, numbers));
return 0;
}
Whenever a task requires finding "all of" something, you should first try to do it in these three steps: Can I put them in some kind of order? Can I find the next one given one? Can I find the first?
So if I asked you to give me all the numbers from 1 to 10 inclusive, how would you do it? Well, it's easy because: You know a simple way to put them in order. You can give me the next one given any one of them. You know which is first. So you start with the first, then keep going to the next until you're done.
This same method applies to this problem. You need three algorithms:
An algorithm that orders the outputs such that each output is either greater than or less than every other possible output. (You don't need to code this, just understand it.)
An algorithm to convert any output into the next output and fail if given the last output. (You do need to code this.)
An algorithm to generate the first output, one less (according to the first algorithm) than every other possible output. (You do need to code this.)
Then it's simple:
Generate the first output (using algorithm 3). Output it.
Use the increment algorithm (algorithm 2) to generate the next output. If there is no next output, stop. Otherwise, output it.
Repeat step 2.
Update: Here are some possible algorithms:
Algorithm 1:
Compare the first digits of the two outputs. If one is greater than the other, that output is greater. If they are equal, continue
Repeat step on moving to successive digits until we find a mismatch.
Algorithm 2:
Start with the rightmost digit.
If this digit is not the maximum it can be, increment it and stop.
Are we at the leftmost digit? If so, stop with error.
Move the digit pointer left one digit.
Algorithm 3:
Set all digits to zero.
“i'm trying to write a program that will give me all possible outcomes if I have n spaces and can place in any number from 0 to m in any one of those spaces.”
Assuming an inclusive “to”, let R = m + 1.
Then this is isomorphic to outputting every number in the range 0 through Rn-1 presented in the base R numeral system.
Which means one outer loop to count (for this you can use the C++ ++ increment operator), and an inner loop to extract and present the digits. For the inner loop you can use C++’ / division operator, and depending on what you find most clear, also the % remainder operator. Unless you restrict yourself to the three choices of R directly supported by the C++ standard library, in which case use the standard formatters.
Note that Rn can get large fast.
So don't redirect the output to your printer, and be prepared to wait for a while for the program to complete.
I think you need to look up recursion. http://www.danzig.us/cpp/recursion.html
Basically it is a function that calls itself. This allows you to perform an N number of nested for loops.

Finding the middle of an array without knowing the length

Find the middle of the string or array with an unknown length. You may
not traverse the list to find the length. You may not use anything to
help you find the length - as it is "unknown." (ie. no sizeof (C) or count(C#) etc...)
I had this question as an interview question. I'm just wondering what the answer is. I did ask if i could use sizeof, he said "no, the size of the string or array is unknown - you just need to get to the middle."
BTW, i'm not sure if this is actually possible to solve with no traversing. I almost felt as though he may have wanted to see how confident i am in my answer :S not sure...
His English was bad - also not sure if this contributed to misunderstandings. He directly told me that i do not need to traverse the list to get to the middle :S :S I'm assuming he meant no traversing at all..... :S
Have two counters, c1 and c2. Begin traversing the list, incrementing c1 every time and c2 every other time. By the time c1 gets to the end, c2 will be in the middle.
You haven't "traversed the list to find the length" and then divided it by two, you've just gone through once.
The only other way I can think of would be to keep taking off the first and last item of the list until you are left with the one(s) in the middle.
You (or your interviewer) are very vague in what the data is (you mentioned "string" and "array"); there's no assumption that can be made, so it can be anything.
You mentioned that the length of the string is unknown, but from your wording it might seem like you (or the interviewer) actually meant to say unknowable.
a) If it's just unknown, then the question is, how can it can be determined? In the case of strings, for example, you can consider the end to be '\0'. You can then apply some algorithms like the ones suggested by the other answers.
b) If it's unknowable, the riddle has no solution. The concept of middle has no meaning without a beginning and an end.
Bottom line, you cannot talk about a middle without a beginning and an end, or a length. Either this question was intentionally unanswerable, or you did not understand it properly. You must know more than just the beginning of the memory segment and maybe its type.
The following code will find the middle of an array WITHOUT traversing the list
int thearray[80];
int start = (int)&thearray;
int end = (int)(&thearray+1);
int half = ((end-start) / 4)/ 2;
std::cout << half << std::endl;
EDITS:
This code assumes you are dealing with an actual array and not a pointer to the first element of one, thus code like:
int *pointer_to_first_element = (int *)malloc(someamount);
will not work, likewise with any other notation that degrades the array reference into a pointer to the first element. Basically any notation using the *.
You would just use the difference between the addresses of the first and last elements.
I think this problem is aimed to also test your skills in problem analysis and requirements gathering. As others have stated before, we will need at least another piece of data to solve this issue.
My approach is to let clear to the interviewer that we can solve the problem with one constraint in the function call: the caller must provide 2 pointer, one to the beginning and another to the end of the array. Given those 2 pointers, and using basic pointer arithmetic, I reach this solution; please let me know what you think about it.
int *findMiddleArray( int const *first, int const *last )
{
if( first == NULL || last == NULL || first > last )
{
return NULL;
}
if( first == last )
{
return (int *)first;
}
size_t dataSize= ( size_t )( first + 1 ) - ( size_t )first,
addFirst= ( size_t )first,
addLast= ( size_t )last,
arrayLen= ( addLast - addFirst) / dataSize + 1,
arrayMiddle= arrayLen % 2 > 0 ? arrayLen / 2 + 1 : arrayLen / 2;
return ( int * )( ( arrayMiddle - 1 ) * dataSize + addFirst );
}
one way you can find midpoint of array is (for odd length array)
just use two loops ,1st loop start traverse from 0 index and the other (nested) loop will traverse from last index of array. Now just compare elements when it comes same ...that will be the mid point of array. i.e if(arr[i]== arr[j]) . Hope you got the point !
For Even length array ..you can do if(arr[i] == arr[j-1]) Or if(arr[i] == arr[j+1]) as they will never be same .try it by dry run!

Finding the maximum weight subsequence of an array of positive integers?

I'm tring to find the maximum weight subsequence of an array of positive integers - the catch is that no adjacent members are allowed in the final subsequence.
The exact same question was asked here, and a recursive solution was given by MarkusQ thus:
function Max_route(A)
if A's length = 1
A[0]
else
maximum of
A[0]+Max_route(A[2...])
Max_route[1...]
He provides an explanation, but can anyone help me understand how he has expanded the function? Specifically what does he mean by
f[] :- [],0
f [x] :- [x],x
f [a,b] :- if a > b then [a],a else [b],b
f [a,b,t] :-
ft = f t
fbt = f [b|t]
if a + ft.sum > fbt.sum
[a|ft.path],a+ft.sum
else
fbt
Why does he expand f[] to [],0? Also how does his solution take into consideration non-adjacent members?
I have some C++ code that is based on this algorithm, which I can post if anyone wants to see it, but I just can't for the life of me fathom why it works.
==========For anyone who's interested - the C++ code ==============
I should add, that the array of integers is to be treated as a circular list, so any sequence containing the first element cannot contain the last.
int memo[55][55];
int solve(int s, int e)
{
if( s>e ) return 0;
int &ret=memo[s][e];
if(ret!=-1)
{
return ret;
}
ret=max(solve(s+1,e), solve(s+2,e)+a[s]);
return ret;
}
class Sequence
{
public:
int maxSequence(vector <int> s)
{
memset(memo,-1);
int n = s.size();
for(int i=0; i<n; i++)
a[i]=s[i];
return max(solve(0,n-2),solve(1,n-1));
}
};
I don't really understand that pseudocode, so post the C++ code if this isn't helpful and I'll try to improve it.
I'm tring to find the maximum weight subsequence of an array of positive integers - the catch is that no adjacent members are allowed in the final subsequence.
Let a be your array of positive ints. Let f[i] = value of the maximum weight subsequence of the sequence a[0..i].
We have:
f[0] = a[0] because if there's only one element, we have to take it.
f[1] = max(a[0], a[1]) because you have the no adjacent elements restriction, so if you have two elements, you can only take one of them. It makes sense to take the largest one.
Now, generally you have:
f[i > 1] = max(
f[i - 2] + a[i] <= add a[i] to the largest subsequence of the sequence a[0..i - 2]. We cannot take a[0..i - 1] because otherwise we risk adding an adjacent element.
f[i - 1] <= don't add the current element to the maximum of a[0..i - 2], instead take the maximum of a[0..i - 1], to which we cannot add a[i].
)
I think this way is easier to understand than what you have there. The approaches are equivalent, I just find this clearer for this particular problem, since recursion makes things harder in this case and the pseudocode could be clearer either way.
But what do you NOT understand? It seems quite clear for me:
we will build the maximal subsequence for every prefix of our given sequence
to calculate the maximal subsequence for prefix of length i, we consider two possibilities: Either the last element is, or isn't in the maximal subsequence (clearly there are no other possibilities).
if it is there, we consider the value of the last element, plus the value of maximal subsequence of the prefix two elements shorter (because in this case, we know the last element cannot be present in the maximal subsequence because of the adjacent elements rule)
if it isn't we take the value of maximal sum of prefix one element shorter (if the last element of the prefix is not in the maximal subsequence, the maximal subsequence has to be equal for this and the previous prefix)
we compare and take the maximum of the two
Plus: you need to remember actual subsequences; you need to avoid superfluous function invocations, hence the memoization.
Why does he expand f[] to [],0?
Because the first from the pair in return value means current maximal subsequence, and the second is its value. Maximal subsequence of an empty sequence is empty and has value zero.