Can we really avoid extra space when all the values are non-negative? - c++

This question is a follow-up of another one I had asked quite a while ago:
We have been given an array of integers and another number k and we need to find the total number of continuous subarrays whose sum equals to k. For e.g., for the input: [1,1,1] and k=2, the expected output is 2.
In the accepted answer, #talex says:
PS: BTW if all values are non-negative there is better algorithm. it doesn't require extra memory.
While I didn't think much about it then, I am curious about it now. IMHO, we will require extra memory. In the event that all the input values are non-negative, our running (prefix) sum will go on increasing, and as such, sure, we don't need an unordered_map to store the frequency of a particular sum. But, we will still need extra memory (perhaps an unordered_set) to store the running (prefix) sums that we get along the way. This obviously contradicts what #talex said.
Could someone please confirm if we absolutely do need extra memory or if it could be avoided?
Thanks!

Let's start with a slightly simpler problem: all values are positive (no zeros). In this case the sub arrays can overlap, but they cannot contain one another.
I.e.: arr = 2 1 5 1 1 5 1 2, Sum = 8
2 1 5 1 1 5 1 2
|---|
|-----|
|-----|
|---|
But this situation can never occur:
* * * * * * *
|-------|
|---|
With this in mind there is algorithm that doesn't require extra space (well.. O(1) space) and has O(n) time complexity. The ideea is to have left and right indexes indicating the current sequence and the sum of the current sequence.
if the sum is k increment the counter, advance left and right
if the sum is less than k then advance right
else advance left
Now if there are zeros the intervals can contain one another, but only if the zeros are on the margins of the interval.
To adapt to non-negative numbers:
Do as above, except:
skip zeros when advancing left
if sum is k:
count consecutive zeros to the right of right, lets say zeroes_right_count
count consecutive zeros to the left of left. lets say zeroes_left_count
instead of incrementing the count as before, increase the counter by: (zeroes_left_count + 1) * (zeroes_right_count + 1)
Example:
... 7 0 0 5 1 2 0 0 0 9 ...
^ ^
left right
Here we have 2 zeroes to the left and 3 zeros to the right. This makes (2 + 1) * (3 + 1) = 12 sequences with sum 8 here:
5 1 2
5 1 2 0
5 1 2 0 0
5 1 2 0 0 0
0 5 1 2
0 5 1 2 0
0 5 1 2 0 0
0 5 1 2 0 0 0
0 0 5 1 2
0 0 5 1 2 0
0 0 5 1 2 0 0
0 0 5 1 2 0 0 0

I think this algorithm would work, using O(1) space.
We maintain two pointers to the beginning and end of the current subsequence, as well as the sum of the current subsequence. Initially, both pointers point to array[0], and the sum is obviously set to array[0].
Advance the end pointer (thus extending the subsequence to the right), and increase the sum by the value it points to, until that sum exceeds k. Then advance the start pointer (thus shrinking the subsequence from the left), and decrease the sum, until that sum gets below k. Keep doing this until the end pointer reaches the end of the array. Keep track of the number of times the sum was exactly k.

Related

Minimum number of jumps

Given an array of N integers arr[] where each element represents the max length of the jump that can be made forward from that element. Find the minimum number of jumps to reach the end of the array (starting from the first element). If an element is 0, then you cannot move through that element.
Note: Return -1 if you can't reach the end of the array.
My code --
int minJumps(int arr[], int n){
int i=0, count=0;
while(i<n-1){
if(arr[i]==0){
return -1;
}
i+=arr[i];
count++;
}
return count;
}
Input:
n=10
arr[ ]=2 3 1 1 2 4 2 0 1 1
So here first jump goes from to 2 to 1, second jump goes from 1 to 1, third jump goes from 1 to 2, fourth jump goes from to 2 to 2, fifth jump goes from 2 to 1 and last sixth jump goes from 1 to 1.
So I got 6 jumps. But the answer is 4 jumps.
If we start particularly from the first element, we can only have one way of going na?
So I think my understanding is wrong, please explain anyone.
There are multiple ways through the array.
The one you described is:
2 1 1 2 2 1 6 jumps
┌───┬─┬─┬───┬───┬─┐
2 3 1 1 2 4 2 0 1 1
But you can also do:
1 3 2 2 1 5 jumps
┌─┬─────┬───┬───┬─┐
2 3 1 1 2 4 2 0 1 1
↑
jump 1 forward, not 2
You can find an optimal solution as:
1 3 1 4 4 jumps
┌─┬─────┬─┬───────┐
2 3 1 1 2 4 2 0 1 1
For any given array, there may be more than one optimal solution.
The trick is to explore them all
Every time you have a decision to make, make them all.
For example, given our first jump of 2, we could also choose to jump 1. Whenever you have a choice like this you will need to build yourself a recursive solution.
Conveniently, you only need to return the minimal number of jumps. You do not actually have to return the jump path. So your function can be written to return exactly that information:
int minJumps( int array[], int size )
The thing that will change is your starting index. You can add that as an additional argument:
int minJumps( int array[], int size, int index = 0 )
Or you can just adjust the array value when you recurse:
... = minJumps( array + n, size - n );
Either way you do the same thing: index a smaller and smaller array.
For example, you can easily answer for this array:
1 zero jumps. (You are at the end of the array)
And this array:
0 zero jumps. (You are at the end of the array)
How about this array:
1 1
Or this array:
5 1
The answer to both is 1 jump, because if we choose a jump-by-1 we get the result of 0 == end of array.
For this array, though:
0 1
The answer is no jumps.
So can you answer for this array?
1 1 1
Or this array?
1 5 1
How about this array?
1 0 1
Aaaannnd... how about these arrays?
2 1 1
2 0 1
The decision factor here is where recursion is useful. Each time you recurse you are working on a smaller array. For the penultimate example, I can get to the end of the array with two possible paths:
┌───┐ 1 jump
2 1 1 2 straight to end works. return 1 jump
┌─┬─┐ 2 jumps
2 1 1 recurse to get 1 jump for the end of the array. return that + 1.
↑
decision point
But there is only one way with:
┌───┐ 1 jump
2 0 1 2 straight to end works. return 1 jump
┌─┬─┐ no jumps
2 0 1 recurse to get -1 for the end of the array.
↑
decision point
With both of these examples we see that the minimum number of jumps is if we choose the jump-by-2.
So, each time you have a decision, take them all. Ignore the bad ones (stuff that returns -1) and choose the smallest number of jumps every time.
Oh, don’t forget to not jump past the end of the array. So
5 1
↑
decision point
Since the array is size 2, you cannot jump more than 1 forward.
Putting it together
Here are the conditions given you:
You have one element in the array. Return 0.
The current element is zero. Return -1. (Cannot advance.)
The current element is n. Recurse for each 1,2,...,n, making sure that you do not exceed the bounds of the array. Return the smallest value you got from your recursive calls.
That’s it! It takes some time to work your mind around recursion, but the main idea is to solve for the simplest case (a single element array), then solve for that with one more element. Or, if I can do a thing to the first element of an array in relation to the rest of the array, then I can do it to the whole array.
Edit: I have written this answer assuming that you have not been given instruction about Graph Theory. If you have, then do as bitmask instructs and look at the algorithms you have been studying. At least one of them will apply to traversing this graph.

How to count the number of permutations?

We are given array-'a' and array-'b' consisting of positive integers.
How can I count all the permutation of array 'a' which are strictly lexicographically smaller than array-'b'?
Arrays can contain as many as 10^5 integers(positive)
Example:
1 2 3 is lexicographically smaller than 3 1 2
1 2 3 is lexicographically smaller than 1 4 5.
I would like the solution to be in C++.
Input : 3
1 2 3
2 1 3
Output : 2
Only permutations 1,2,3 and 1,3,2 are lexicographically smaller than 2 1 3
Let's just tackle the algorithm. Once you get that figured out, the implementation should be pretty straightforward. Does this look like it does what you're looking for?
Pseudo code:
function get_perms(a,b)
#count the number of digits in a that are <b[0]
count = sum(a<b[0])
Nperms = (len(a)-1)! #modify this formula as needed
N = count*Nperms
if sum(a==b[0]) > 0
remove 1 b[0] from a
# repeat the process with the substring assuming a[0]==b[0]
N += sum(a==b[0])*get_perms(a,b[1:end])
return N
main()
get_perms(a,b)
Edit: I did a little searching. I believe that this is what you are looking for.

Intuition behind working with `k` to find the kth-symbol in the grammar

I took part in a coding contest wherein I encountered the following question:
On the first row, we write a 0. Now in every subsequent row, we look at the previous row and replace each occurrence of 0 with 01, and each occurrence of 1 with 10. Given row N and index K, return the K-th indexed symbol in row N. (The values of K are 1-indexed.)
While solving the question, I solved it like a level-order traversal of a tree, trying to form the new string at each level. Unfortunately, it timed-out. I then tried to think along the terms of caching the results, etc. with no luck.
One of the highly upvoted solutions is like this:
class Solution {
public:
int kthGrammar(int N, int K) {
if (N == 1) return 0;
if (K % 2 == 0) return (kthGrammar(N - 1, K / 2) == 0) ? 1 : 0;
else return (kthGrammar(N - 1, (K + 1) / 2) == 0) ? 0 : 1;
}
};
My question is simple - what is the intuition behind working with the value of K (especially, the parities of K)? (I hope to be able to identify such questions when I encounter them in future).
Thanks.
Look at the sequence recursively. In generating a new row, the first half is identical to the process you used to get the previous row, so that part of the expansion is already done. The second half is merely the same sequence inverted (0 for 1, 1 for 0). This is one classic way to generate a parity map: flip all the bits and append, representing adding a 1 to the start of each binary number. Thinking of expanding the sequence 0-3 to 0-7, we start with
00 => 0
01 => 1
10 => 1
11 => 0
We now replicate the 2-digit sequence twice: first with a leading 0, which preserves the original parity; second with a leading 1, which inverts the parity.
000 => 0
001 => 1
010 => 1
011 => 0
100 => 1
101 => 0
110 => 0
111 => 1
Is that an intuition that works for you?
Just for fun, as a different way to solve this, consider that the nth row (0-indexed) has 2^n elements in it, and a determination as to the value of the kth (0-indexed) element can be made soley according to the parity of how many bits are set in k.
The check for parity in the code you posted is just to make the division by two correct, there's no advanced math or mystery hiding here :) Since the pattern is akin to a tree, where the pattern size multiplies by two for each added row, correctly dividing points to the element's parent. The indexes in this question are said to be "1-indexed;" if the index is 2, dividing by two yields the parent index (1) in the row before; and if the index is 1, dividing (1+1) by two yields that same parent index. I'll leave it to the reader to generalize that to ks parity. After finding the parent, the code follows the rule stated in the question: if the parent is 0, the left-child must be 0 and right-child 1, and vice versa.
0
0 1
0 1 1 0
0 1 1 0 1 0 0 1
0 1 1 0 1 0 0 1 1 0 0 1 0 1 1 0
a a b a b b a
0 01 0110 01101001 0110100110010110
a b b a b a a b
0110100110010110 1001011001101001

How do I generate all vectors of size n where each element may contain 1 of m different values?

Sorry if this is a duplicate, but I did not find any answers which match mine.
Consider that I have a vector which contains 3 values. I want to construct another vector of a specified length from this vector. For example, let's say that the length n=3 and the vector contains the following values 0 1 2. The output that I expect is as follows:
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 1 2
0 2 0
0 2 1
0 2 2
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
1 1 2
1 2 0
1 2 1
1 2 2
2 0 0
2 0 1
2 0 2
2 1 0
2 1 1
2 1 2
2 2 0
2 2 1
2 2 2
My current implementation simply constructs for loops based on nand generates the expected output. I want to be able to construct output vectors of different lengths and with different values in the input vector.
I have looked at possible implementations using next_permutation, but unfortunately passing a length value does not seem to work.
Are there time and complexity algorithms that one can use for this case? Again, I might have compute this for up to n=17and sizeof vector around 6.
Below is my implementation for n=3. Here, encis the vector which contains the input.
vector<vector<int> > combo_3(vector<double>enc,int bw){
vector<vector<int> > possibles;
for (unsigned int inner=0;inner<enc.size();inner++){
for (unsigned int inner1=0;inner1<enc.size();inner1++){
for (unsigned int inner2=0;inner2<enc.size();inner2++){
cout<<inner<<" "<<inner1<<" "<<inner2<<endl;
unsigned int arr[]={inner,inner1,inner2};
vector<int>current(arr,arr+sizeof(arr)/sizeof(arr[0]));
possibles.push_back(current);
current.clear();
}
}
}
return possibles;
}
What you are doing is simple counting. Think of your output vector as a list of a list of digits (a vector of a vector). Each digit may have one of m different values where m is the size of your input vector.
This is not permutation generation. Generating every permutation means generating every possible ordering of an input vector, which is not what you're looking for at all.
If you think of this as a counting problem the answer may become clearer to you. For example, how would you generate all base 10 numbers with 5 digits? In that case, your input vector has size 10, and each vector in your output list has length 5.

How to find and return a repeating sequence within a vector

I have a vector that is filled dynamically and will always contain a repeating sequence with characters and length that I am unsure of. For example, the vector could contain these elements:
0 1 1 2 3 1 0 1 1 2 3 1 0 1 1 2
and the repeating sequence in that vector is:
0 1 1 2 3 1
How can I search the vector and find those elements. I would like to put the found sequence in a new vector. I assumed at first it would only take a simple for loop and checking for repetition of the first and second element in the array, so in the case above I would exit the loop when I reached 0 1 a second time, but the problem is that it cannot be assumed that the first 2 elements will be in the repeating pattern, so
0 1 2 3 2 3 2 3 2 3
can be valid elements in the vector. Any ideas?
in general (infinite result) it is impossible to know the sequence because something like that can happen 1 million 0 and then 1,after 1000 zero u will think that the sequence is zero only,but if the vector is finite
you can write somethink like that
for(I..VECTORSIZE / 2)
if(VECTORSIZE % I == 0)
CHECK IF SUBVECTOR(0,I) == SUBVECTOR(I,I*2) == SUBVECTOR(I*2,I*3)....
return I
else continute;