💡 The recursion explores new branches starting with queen at (0,1).
reconstruct
End of Search, Return Total Solutions
All recursive calls complete, returning the total count of 2 valid solutions for the 4-queens problem.
💡 The final count aggregates all valid leaf nodes found during recursion.
Line:return backtrack(0, 0, 0, 0)
💡 The algorithm efficiently counted all solutions without enumerating invalid boards.
class Solution:
def totalNQueens(self, n: int) -> int:
def backtrack(row, cols, pos_diags, neg_diags):
# STEP 1: Check if all rows are placed
if row == n:
return 1
count = 0
# STEP 2: Calculate available positions
available_positions = ((1 << n) - 1) & ~(cols | pos_diags | neg_diags)
while available_positions:
# STEP 3: Extract rightmost available position
position = available_positions & -available_positions
# STEP 4: Remove chosen position
available_positions &= available_positions - 1
# STEP 5: Recurse with updated bitmasks
count += backtrack(row + 1,
cols | position,
(pos_diags | position) << 1,
(neg_diags | position) >> 1)
return count
return backtrack(0, 0, 0, 0)
📊
N-Queens II (Count Solutions) - Watch the Algorithm Execute, Step by Step
Watching the algorithm step through each recursive call and bitmask update reveals how pruning and bit operations efficiently solve the problem without brute force.
✓ Bitmasking efficiently encodes and updates constraints for columns and diagonals, enabling fast pruning.
This insight is hard to see from code alone because bit operations are compact and abstract, but visualization shows how constraints evolve.
✓ The recursion tree structure clearly shows how the algorithm explores each row's queen placements and backtracks when no options remain.
Seeing the tree helps understand the exhaustive search and pruning, which is less obvious from reading code.
✓ Each leaf node corresponds to a complete valid solution, and the algorithm counts these leaves to find the total number of solutions.
Understanding that counting solutions is about counting leaf nodes clarifies the base case and return values.
Practice
(1/5)
1. You need to generate all combinations of balanced parentheses pairs for a given number n. Which algorithmic approach guarantees generating only valid sequences without generating invalid ones first?
easy
A. Brute force: generate all possible sequences of '(' and ')' of length 2n, then filter valid ones
B. Backtracking with pruning: build sequences by adding '(' or ')' only when it keeps the sequence valid
C. Greedy approach: always add '(' until n is reached, then add ')' to close all opened parentheses
D. Dynamic programming: count the number of valid sequences using Catalan number formula
Solution
Step 1: Understand problem constraints
We want to generate all valid parentheses sequences without generating invalid ones first.
Step 2: Analyze approaches
Brute force generates all sequences including invalid ones, greedy fails to generate all valid sequences, DP counts sequences but does not generate them. Backtracking with pruning adds '(' or ')' only when valid, thus generating only valid sequences.
Final Answer:
Option B -> Option B
Quick Check:
Backtracking with pruning avoids invalid sequences [OK]
Hint: Backtracking prunes invalid sequences early [OK]
Common Mistakes:
Thinking greedy can generate all valid sequences
Confusing counting with generating sequences
2. Given the following code snippet for getPermutation, what is the returned value when calling getPermutation(3, 3)?
easy
A. '123'
B. '312'
C. '213'
D. '231'
Solution
Step 1: Trace factorial array computation
factorial = [1, 1, 2] for n=3.
Step 2: Calculate indices and build result
k=3 -> k=2 zero-based. For i=2: idx=2//2=1, pick '2'. For i=1: k=2%2=0, idx=0//1=0, pick '1'. For i=0: k=0%1=0, idx=0//1=0, pick '3'. Result = '213'.
Hint: Remember to convert k to zero-based before indexing [OK]
Common Mistakes:
Off-by-one error in k adjustment
Wrong index calculation in loop
Not popping used numbers
3. Consider this modified code snippet for generating parentheses. Which line contains a subtle bug that can cause invalid sequences to be generated?
medium
A. Line with 'if close_count <= open_count:' condition
B. Line with 's.pop()' after backtrack calls
C. Line with 'if open_count < n:' condition
D. Line with 'if len(s) == 2 * n:' base case
Solution
Step 1: Examine close_count condition
The condition 'close_count <= open_count' allows adding ')' even when close_count equals open_count, which can produce invalid sequences.
Step 2: Correct condition
The correct condition is 'close_count < open_count' to ensure ')' is added only when there are unmatched '('.
Final Answer:
Option A -> Option A
Quick Check:
Changing to '<' fixes invalid sequence generation [OK]
Hint: Close count must be strictly less than open count [OK]
Common Mistakes:
Using <= instead of < for close_count condition
Forgetting to pop after recursion
4. What is the time complexity of the optimal backtracking algorithm that generates unique permutations of an array with duplicates by sorting and skipping duplicates during recursion?
medium
A. O(n! * log n) due to sorting and binary search for duplicates
B. O(n! * n^2) because each permutation requires copying the array and checking duplicates
C. O(n^n) because the recursion explores all possible swaps without pruning
D. O(n! * n) because pruning duplicates early reduces redundant branches but each permutation still requires O(n) copying
Solution
Step 1: Identify complexity of outer and inner loops
Backtracking explores permutations, which is O(n!). Each permutation requires copying O(n) elements to result.
Step 2: Check if pruning duplicates reduces complexity
Pruning duplicates early avoids redundant branches, so complexity is O(n! * n), not worse. Sorting is O(n log n) but done once.
Final Answer:
Option D -> Option D
Quick Check:
Pruning reduces branches but copying each permutation costs O(n) [OK]
Hint: Pruning duplicates reduces branches but copying costs O(n) per permutation [OK]
Common Mistakes:
Confusing pruning effect or ignoring copy cost
5. Suppose you want to modify the palindrome partitioning algorithm to allow reuse of substrings in partitions (i.e., substrings can appear multiple times in different partitions). Which change to the algorithm is necessary to correctly handle this variant without losing valid partitions or causing duplicates?
hard
A. Memoize palindrome checks and reuse results but keep backtracking unchanged
B. Modify backtracking to avoid popping from path to reuse substrings across calls
C. Use a global visited set to skip substrings already used in previous partitions
D. Allow substrings to be reused by resetting path after each complete partition
Solution
Step 1: Understand reuse requirement
Reusing substrings means substrings can appear multiple times in different partitions, so path management must allow multiple uses.
Step 2: Identify necessary algorithm change
Memoizing palindrome checks improves efficiency by avoiding repeated palindrome computations, while backtracking logic remains unchanged to generate all valid partitions.
Final Answer:
Option A -> Option A
Quick Check:
Memoization optimizes palindrome checks without affecting partition generation correctness [OK]
Hint: Memoize palindrome checks to optimize without changing backtracking [OK]
Common Mistakes:
Assuming popping affects substring reuse
Using visited sets that block valid reuse
Resetting path incorrectly losing partitions
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.