LeetCode Daily Challenge-3304. Find the K-th Character in String Game I(Easy)

Table of contents

- LeetCode Link
- Date: 3rd July 2025
- Topics:
Math
,Bit Manipulation
,Recursion
,Simulation
Problem Understanding
LeetCode 3304 presents an interesting string transformation game where Alice starts with "a"
and repeatedly applies an operation: for each character in the current string, append its next character in the alphabet to create a new string.
Problem Statement
- Initial state:
word = "a"
- Operation: For each character
c
inword
, appendnext(c)
toword
- Goal: Find the k-th character (1-indexed) after sufficient operations
- Key rule:
'z'
wraps around to'a'
Example Walkthrough
Initially: word = "a"
Round 1: "a" → "ab" (append 'b')
Round 2: "ab" → "abbc" (append 'b' then 'c')
Round 3: "abbc" → "abbcbccd" (append 'b','c','c','d')
For k = 5
: The 5th character is 'b'
Two Solution Approaches
Approach 1: Pattern Recognition (Elegant)
The elegant solution recognizes that the answer is simply 'a' + popcount(k - 1)
where popcount(x)
counts the number of 1s in the binary representation of x.
Approach 2: Recursive Divide and Conquer (Our Focus)
The provided C solution uses a recursive approach that mirrors the binary structure of the problem.
The C Solution Deep Dive
char dfs(int k, int level);
char kthCharacter(int k) {
int level = 0;
int len = 1;
// Find the level such that total length >= k
while (len < k) {
len *= 2;
level++;
}
return dfs(k, level);
}
char dfs(int k, int level) {
if (level == 0) return 'a'; // base case: word = "a"
int half = 1 << (level - 1); // length of W(level - 1)
if (k <= half) {
return dfs(k, level - 1); // first half
} else {
char c = dfs(k - half, level - 1); // second half (shifted)
return c == 'z' ? 'a' : c + 1;
}
}
Algorithm Breakdown
Step 1: Find the Required Level
int level = 0;
int len = 1;
while (len < k) {
len *= 2;
level++;
}
Purpose: Determine the minimum number of rounds needed to have at least k
characters.
Logic: Each round doubles the string length:
- Level 0: length = 1 (
"a"
) - Level 1: length = 2 (
"ab"
) - Level 2: length = 4 (
"abbc"
) - Level 3: length = 8 (
"abbcbccd"
)
Step 2: Recursive Structure Analysis
The key insight is that at each level, the string has a binary tree structure:
Level 0: "a"
|
Level 1: "a" + "b"
| |
Level 2: "ab" + "bc"
| |
Level 3: "abbc" + "bccd"
Step 3: Divide and Conquer Logic
int half = 1 << (level - 1); // length of W(level - 1)
if (k <= half) {
return dfs(k, level - 1); // first half
} else {
char c = dfs(k - half, level - 1); // second half (shifted)
return c == 'z' ? 'a' : c + 1;
}
Key Insights:
- First Half: Characters 1 to
half
are identical to the previous level - Second Half: Characters
half+1
to2*half
are the "next" characters of the previous level - Position Mapping: Position
k
in second half corresponds to positionk-half
in previous level
Visual Example: Finding the 5th Character
Target: k = 5
Level needed: 3 (since 2^3 = 8 >= 5)
Level 3: "abbcbccd" (length 8)
positions: 1 2 3 4 5 6 7 8
half = 4, k = 5 > 4, so we're in the second half
Position 5 maps to position 1 in the previous level
Level 2: "abbc" (length 4)
positions: 1 2 3 4
Position 1 → character 'a'
Since we're in the second half, we increment: 'a' + 1 = 'b'
Step-by-Step Execution
Let's trace dfs(5, 3)
:
dfs(5, 3):
half = 4
,k = 5 > 4
→ second half- Call
dfs(5-4, 2)
=dfs(1, 2)
- Result will be incremented
dfs(1, 2):
half = 2
,k = 1 ≤ 2
→ first half- Call
dfs(1, 1)
dfs(1, 1):
half = 1
,k = 1 ≤ 1
→ first half- Call
dfs(1, 0)
dfs(1, 0):
- Base case: return
'a'
- Base case: return
Back to dfs(1, 1): returns
'a'
- Back to dfs(1, 2): returns
'a'
- Back to dfs(5, 3): increments
'a'
→ returns'b'
Time and Space Complexity
Time Complexity
- Finding level: O(log k)
- Recursive calls: O(log k) levels, each with O(1) work
- Total: O(log k)
Space Complexity
- Recursion stack: O(log k)
- Variables: O(1)
- Total: O(log k)
Key Optimizations
1. Level Pre-computation
Instead of building the entire string, we calculate the minimum level needed upfront.
2. Binary Structure Exploitation
Each level has exactly double the length of the previous level, allowing efficient position mapping.
3. Character Wrapping
return c == 'z' ? 'a' : c + 1;
Handles the wrap-around from 'z' to 'a' elegantly.
Alternative Implementations
Iterative Version
char kthCharacter(int k) {
int shifts = 0;
k--; // Convert to 0-indexed
while (k > 0) {
if (k & 1) shifts++; // Count 1s in binary
k >>= 1;
}
return 'a' + (shifts % 26);
}
Mathematical One-liner
char kthCharacter(int k) {
return 'a' + __builtin_popcount(k - 1);
}
Common Pitfalls and Debug Tips
1. Off-by-One Errors
// Remember: problem uses 1-based indexing
int half = 1 << (level - 1);
if (k <= half) {
return dfs(k, level - 1);
} else {
return dfs(k - half, level - 1); // Correct offset
}
2. Character Wrapping
// Handle 'z' → 'a' transition
return c == 'z' ? 'a' : c + 1;
3. Level Calculation
// Ensure we have enough characters
while (len < k) {
len *= 2;
level++;
}
Test Cases
void test_solution() {
assert(kthCharacter(1) == 'a'); // Base case
assert(kthCharacter(2) == 'b'); // First transformation
assert(kthCharacter(5) == 'b'); // Example from problem
assert(kthCharacter(10) == 'c'); // Larger case
}
Why This Approach Works
1. Binary Tree Structure
The string growth follows a perfect binary tree pattern where:
- Each node represents a character
- Left child = same character
- Right child = next character
2. Recursive Decomposition
Any position k can be decomposed into:
- Which half it belongs to
- Its relative position within that half
- The transformation applied to reach that half
3. Efficient Navigation
Instead of building the entire string, we navigate directly to the target position using the binary structure.
Conclusion
The recursive divide-and-conquer approach elegantly solves this problem by recognizing the underlying binary tree structure. While the mathematical solution (popcount
) is more concise, the recursive approach provides deeper insights into the problem's structure and is more intuitive for understanding the transformation process.
Key Takeaways:
- Pattern Recognition: Look for binary/tree structures in growth problems
- Divide and Conquer: Break down positions into manageable subproblems
- Recursive Thinking: Each level builds upon the previous in a predictable way
- Mathematical Insight: Sometimes elegant patterns hide behind complex transformations
The solution demonstrates how a seemingly complex string transformation can be solved efficiently through structural analysis and recursive decomposition.
Subscribe to my newsletter
Read articles from Anni Huang directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Anni Huang
Anni Huang
I am Anni HUANG, a software engineer with 3 years of experience in IDE development and Chatbot.