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

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

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.

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

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.

Extract all possible ordered sub-sets

I have a set of elements from which I want to extract ordered subsets. What I mean by ordered subsets is that I cannot switch elements inside the set. I gave three examples to show how I am trying to solve the problem.
How can I extract these subsets recursively?
Do you have any pseudo-code in mind?
{ . } = subset
Example 1
Let S = {f1,f2,f3} be a set composed of 3 elements. I want to extract all the possible ordered sub-sets as follows:
-{f1},{f2},{f3} // {f1} is a subset, {f2} is a subset etc.
-{f1,f2},{f3} // {f1,f2} form a subset and {f3} is also a subset
-{f1},{f2,f3} // {f1} is a subset and {f2,f3} form a subset
Example 2
Let S = {f1,f2,f3,f4} be set a composed of 4 elements.
Possible ordered subsets:
-{f1},{f2},{f3},{f4}
-{f1,f2},{f3,f4}
-{f1},{f2,f3},{f4}
-{f1},{f2},{f3,f4}
-{f1,f2,f3}{f4}
-{f1},{f2,f3,f4}
-{f1,f2},{f3},{f4}
-{f1,f2,f3,f4}
Example 3
Let S = {f1,f2,f3,f4,f5} be set a composed of 5 elements.
Possible ordered subsets:
-{f1},{f2},{f3},{f4},{f5}
-{f1,f2},{f3},{f4},{f5}
-{f1},{f2,f3},{f4},{f5}
-{f1},{f2},{f3,f4},{f5}
-{f1},{f2},{f3},{f4,f5}
-{f1,f2},{f3,f4},{f5}
-{f1},{f2,f3},{f4,f5}
-{f1,f2,f3},{f4,f5}
-{f1,f2,f3},{f4},{f5}
-{f1},{f2,f3,f4},{f5}
-{f1},{f2},{f3,f4,f5}
-{f1,f2},{f3,f4,f5}
-{f1,f2,f3,f4}{f5}
-{f1},{f2,f3,f4,f5}
- etc...
If an array contains the set, modify the array such that there is one space between every element. This space is reserved for partitioning. Take any naming convention. 0 implies no partition whereas 1 implies partition. Now traverse through the array to recursively add 1 or 0 in the partition. All possible combinations can be generated.
Taking Example 1:
S = {f1,f2,f3}
S'= {f1,0,f2,0,f3}
So the subsets will be:
{f1,0,f2,0,f3}, {f1,0,f2,1,f3}, {f1,1,f2,0,f3}, {f1,1,f2,1,f3}
which is same as:
{f1,f2,f3}, {{f1,f2},{f3}}, {{f1},{f2,f3}}, {{f1},{f2},{f3}}
If you don't want the original set to appear in the set of all subsets, just don't consider the state where every partition contains 0.
Let's say set S = {a,b,c,d} contain 4 elements. All the subsets can be generated by writing 2 ^ n - 1 in binary and subsequent subtraction.
a b c d
1 1 1 1 => (a b c d)
1 1 1 0 => (a b c)(d)
1 1 0 1 => (a b d)(c) //The logic is to club all the 1's together
1 1 0 0 => (a b) now 0 0 can be further broken down into (1 1) => (c d) , (1 0) => (c)(d)
1 0 1 1 => (a c d)(b)
1 0 1 0 => (a c) now 0 0 can be further broken down into (1 1) => (b d ), (1 0 ) => (b)(d)
1 0 0 1 => (a d) same steps as above
1 0 0 0 => (a) now left with 3 zeros we have b c d as 3 sets now we can start afresh with 1 1 1 and then go to 1 1 0 and so on.
In this way we are able to generate all the subsets.

algorithm transfer one coin matrix to another coin matrix

Description:
There are m * n (m <= 100, n <=100) coins on the desktop forming a m row n column coin matrix. Every coin either face upward, or face backward, represented by 0 or 1.
Rules of the game are:
(1) every time, you are allowed to inverse one row of coins.
(2) every time, you are allowed to swap two columns.
Object:
from initial matrix -> target matrix
Input:
1. k the count of test caese
2. m n the count of rows and columns
3. the numbers of the inital matrix and the target matrix
Output
the least steps from initial matrix to target matrix, if it is not possible to transfer from initial to target, output -1.
sample intput
2
4 3
1 0 1
0 0 0
1 1 0
1 0 1
1 0 1
1 1 1
0 1 1
1 0 1
4 3
1 0 1
0 0 0
1 0 0
1 1 1
1 1 0
1 1 1
0 1 1
1 0 1
sample output
2
-1
I have coded one solution: mysolution.cc, which enumerate all posibilities and which is correct but it is too slow, could you provide a correct but fast solution.
Thanks.
The rows always stay in the same place, so if row r starts with k ones, it will always have either k ones or columns - k.
for each row, check if count_of_ones(initial,row) == count_of_ones(target,row), if yes, fine, else check if count_of_ones(initial,row) = columns - count_of_ones(target,row), if so, flip row, else output -1. As #maniek pointed out, it's not so easy when exactly half of the columns contain ones. Such rows would have to be treated in step 2 to try and form the required columns.
for each column, count the number of ones int the target and the working matrix (after flipping rows as appropriate). If the sequences of counts are not permutations of each other, output -1, otherwise try to find a permutation of columns that transforms working to target (any columns identical between working and target have to be kept fixed). If not possible, output -1, otherwise find minimum number of swaps necessary to achieve that permutation.
I will give you some thoughts. You compare row by row. If the i-th row of the first matrix has the same number of 1 as in the i-th row of the second matrix - then you don't inverse. If the i-th row of the first matrix has the same number of 1 as the 0 in the i-th row of the second matrix - then you must inverse. If neither of this is true, then there is no solution. This is all about inversing.
Now all columns are equal but in a different order(the second matrix has permuted columns from the first matrix). If the columns are not permutation of each other - return -1. This problem is equal to find the minimum number of swaps to convert a one permutation to other.

C++ Novice regarding Bitset operations with strings

I'm currently learning about bitset, and in one paragraph it says this about their interactions with strings:
"The numbering conventions of strings and bitsets are inversely related: the rightmost character in the string--the one with the highest subscript--is used to initialize the low order bit in the bitset--the bit with subscript 0."
however later on they give an example + diagram which shows something like this:
string str("1111111000000011001101");
bitset<32> bitvec5(str, 5, 4); // 4 bits starting at str[5], 1100
value of str:
1 1 1 1 1 (1 1 0 0) 0 0 0 ...
value of bitvec5:
...0 0 0 0 0 0 0 (1 1 0 0)
This example shows it taking the rightmost bit and putting it so the last element from the string is the last in the bitset, not the first.
Which is right?(or are both wrong?)
They are both right.
Traditionally the bits in a machine word are numbered from right to left, so the lowest bit (bit 0) is to the right, just like it is in the string.
The bitset looks like this
...1100 value
...3210 bit numbers
and the string that looks the same
"1100"
will have string[0] == '1' and string[3] == '0', the exact opposite!
string strval("1100"); //1100, so from rightmost to leftmost : 0 0 1 1
bitset<32> bitvec4(strval); //bitvec4 is 0 0 1 1
So whatever you are reading is correct(both text and example) :
the rightmost character in the string--the one with the highest
subscript--is used to initialize the low order bit in the bitset--the
bit with subscript 0.