779. K-th Symbol in Grammar - Explanation
Description
The first row of a table is 0. To produce the next row, replace every 0 with 01 and every 1 with 10, keeping their order. Return the symbol at position k in row n. Both rows and positions are numbered starting at 1.
Example 1:
Input: n = 3
k = 3
Output: 1Explanation: Row 3 is 0110, whose third symbol is 1.
Example 2:
Input: n = 4
k = 5
Output: 1Explanation: Row 4 is 01101001, so its fifth symbol is 1.
Example 3:
Input: n = 4
k = 8
Output: 1Explanation: The eighth and final symbol of row 4, 01101001, is 1.
Constraints:
1 <= n <= 301 <= k <= 2^(n - 1)
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Recursion - Tracing values back through parent-child relationships in a recursive structure
- Binary Tree Concepts - Understanding how positions in a row relate to parent positions in the previous row
- Bit Manipulation - Using XOR for flipping values and bit counting to determine parity
- Binary Search - Narrowing down position ranges by halving the search space
1. Brute Force
Intuition
The problem generates rows where each row is built from the previous one: 0 becomes 01 and 1 becomes 10. The most straightforward approach is to actually build each row until we reach row n, then return the character at position k. While simple to understand, this approach becomes impractical for large n since each row doubles in size.
Algorithm
- Start with the first row containing just
0. - For each subsequent row up to
n:- Create a new row by replacing each
0with01and each1with10.
- Create a new row by replacing each
- Return the character at index
k - 1from the final row.
Time & Space Complexity
- Time complexity:
- Space complexity:
2. Binary Tree Traversal (Recursion)
Intuition
We can visualize the grammar as a binary tree where each node generates two children. The key insight is that the position k in row n has a parent at position ceil(k/2) in row n-1. If k is in the left half of the current row, it inherits the parent's value directly. If k is in the right half, its value is the flip of the parent. This lets us trace from position k back to the root without building any rows.
Algorithm
- Define a recursive function
dfs(n, k, root)whereroottracks the current value. - Base case: if
n == 1, return the currentrootvalue. - Calculate
total = 2^(n-1), the size of rown. - If
k > total / 2, we're in the right half:- Recurse with
n - 1, adjustkby subtracting half, and fliprootusing XOR.
- Recurse with
- Otherwise, recurse with the same
rootvalue. - Start with
dfs(n, k, 0)since row 1 starts with0.
Time & Space Complexity
- Time complexity:
- Space complexity: for recursion stack.
3. Binary Tree Traversal (Iteration)
Intuition
This is the iterative version of the binary tree approach. Instead of recursion, we use a loop to perform binary search on the position. We maintain a range [left, right] representing the current segment and track whether the value flips as we narrow down to position k. Each iteration halves the search space until we've processed all n - 1 levels.
Algorithm
- Initialize
cur = 0(the root value) and setleft = 1,right = 2^(n-1). - Loop
n - 1times:- Calculate
mid = (left + right) / 2. - If
k <= mid, narrow to the left half by settingright = mid. - Otherwise, narrow to the right half, set
left = mid + 1, and flipcur.
- Calculate
- Return
curas the final answer.
Time & Space Complexity
- Time complexity:
- Space complexity:
4. Recursion (Traverse Towards Root)
Intuition
Each position in row n comes from a parent position in row n-1. If position k is odd, it's a left child and has the same value as its parent at position (k+1)/2. If k is even, it's a right child and has the opposite value. We recursively trace back to row 1 (which is always 0) and determine the value based on how many flips occurred.
Algorithm
- Base case: if
n == 1, return0. - If
kis odd, returnkthGrammar(n - 1, (k + 1) / 2)since left children inherit parent value. - If
kis even, returnkthGrammar(n - 1, k / 2) XOR 1since right children flip.
Time & Space Complexity
- Time complexity:
- Space complexity: for recursion stack.
5. Math
Intuition
There's an elegant mathematical pattern here. The value at position k depends on how many times we flip while tracing from k back to the root. Each flip happens when we're a right child, which corresponds to a 1 bit in the binary representation of k - 1. So the answer is simply the parity (odd or even) of the number of 1 bits in k - 1.
Algorithm
- Convert
k - 1to binary. - Count the number of
1bits. - Return the count modulo 2 (i.e.,
count & 1).
Time & Space Complexity
- Time complexity:
- Space complexity: or depending on the language.
Common Pitfalls
Using 0-Indexed vs 1-Indexed Position
The problem uses 1-indexed positions for k, but many solutions require converting to 0-indexed logic. A common mistake is forgetting to subtract 1 when counting bits or when comparing positions. For the bit-counting solution, you must use k - 1 (not k) to correctly count the number of flips from the root.
Integer Overflow When Computing Row Size
When calculating the size of row n as 2^(n-1), this can overflow for large values of n (up to 30 in the constraints). Using 1 << (n - 1) is safe in most languages for n <= 30, but be careful with signed 32-bit integers when n = 31 or higher. Always ensure your bit-shift operations use appropriate integer types.
Confusing Left Child vs Right Child Logic
In the recursive solutions, the logic for determining whether a position is a left child or right child is subtle. Left children (odd k values) inherit the parent's value, while right children (even k values) flip it. Mixing up this logic or incorrectly computing the parent position (k + 1) / 2 vs k / 2 leads to wrong answers.
Sign in to join the discussion