Bird
Raised Fist0
Interview PreptrieshardAmazonFacebookGoogleBloomberg

Word Search II (Multiple Words in Grid)

Choose your preparation mode4 modes available
📋
Problem

Imagine you have a giant crossword puzzle and a huge dictionary of words. You want to find all the words from the dictionary that appear in the puzzle by connecting adjacent letters.

Given a 2D board of characters and a list of words, find all words in the board. Each word must be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.

1 <= board.length, board[i].length <= 121 <= words.length <= 3 * 10^41 <= words[i].length <= 10board and words consist of lowercase English letters
Edge cases: Empty board → returns empty listEmpty words list → returns empty listWords with repeated letters requiring careful backtracking → correct detection
</>
IDE
def findWords(board: List[List[str]], words: List[str]) -> List[str]:public List<String> findWords(char[][] board, String[] words)vector<string> findWords(vector<vector<char>>& board, vector<string>& words)function findWords(board, words)
def findWords(board, words):
    # Write your solution here
    pass
class Solution {
    public List<String> findWords(char[][] board, String[] words) {
        // Write your solution here
        return new ArrayList<>();
    }
}
#include <vector>
#include <string>
using namespace std;

vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
    // Write your solution here
    return {};
}
function findWords(board, words) {
    // Write your solution here
}
Coming soon
0/9
Common Bugs to Avoid
Wrong: Missing some valid wordsDFS does not explore all paths or trie pruning is incorrect.✅ Implement full DFS with backtracking and prune using trie prefixes.
Wrong: Includes invalid words not present in boardNo prefix pruning or incorrect visited cell tracking.✅ Use trie to prune invalid prefixes and mark visited cells properly.
Wrong: Crashes or errors on empty board or wordsNo guard clauses for empty inputs.✅ Add checks for empty board or empty words before processing.
Wrong: Reuses cells multiple times in same wordVisited cells not tracked or unmarked correctly.✅ Track visited cells per DFS path and unmark after recursion.
Wrong: Solution times out on large inputsBrute force DFS per word without trie pruning.✅ Build trie for all words and prune DFS paths early.
✓
Test Cases
t1_01basic
Input{"board":[["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]],"words":["oath","pea","eat","rain"]}
Expected["eat","oath"]

The words 'eat' and 'oath' can be formed by adjacent letters in the board, while 'pea' and 'rain' cannot.

t1_02basic
Input{"board":[["a","b"],["c","d"]],"words":["ab","abc","abd","abcd","acdb"]}
Expected["ab","acdb"]

Only 'ab' and 'acdb' can be formed by adjacent letters in the small 2x2 board; 'abc', 'abd', and 'abcd' cannot be formed due to adjacency constraints.

t2_01edge
Input{"board":[],"words":["a","b"]}
Expected[]

Empty board cannot form any words.

t2_02edge
Input{"board":[["a"]],"words":[]}
Expected[]

Empty words list means no words to find.

t2_03edge
Input{"board":[["a","a","a"],["a","a","a"],["a","a","a"]],"words":["aaa","aaaa","aaaaa"]}
Expected["aaa","aaaa","aaaaa"]

Board with all identical letters can form words with repeated letters requiring careful backtracking.

t3_01corner
Input{"board":[["a","b","c"],["a","e","d"],["a","f","g"]],"words":["abcdefg","gfedcba"]}
Expected["abcdefg"]

Greedy approach fails here: only 'abcdefg' can be formed by adjacent letters, 'gfedcba' cannot.

t3_02corner
Input{"board":[["a","b","c"],["d","e","f"],["g","h","i"]],"words":["abc","abcdef","abcdefghi"]}
Expected["abc","abcdef","abcdefghi"]

Tests confusion between 0/1 usage of cells: each cell can be used once per word, not unlimited times.

t3_03corner
Input{"board":[["a","b","c","d"],["e","f","g","h"],["i","j","k","l"]],"words":["afk","bfj","cgl","dhl"]}
Expected["afk","bfj","cgl","dhl"]

Tests off-by-one errors in indexing neighbors and DFS boundaries.

t4_01performance
Input{"board":[["a","b","c","d","e","f","g","h","i","j","k","l"],["m","n","o","p","q","r","s","t","u","v","w","x"],["y","z","a","b","c","d","e","f","g","h","i","j"],["k","l","m","n","o","p","q","r","s","t","u","v"],["w","x","y","z","a","b","c","d","e","f","g","h"],["i","j","k","l","m","n","o","p","q","r","s","t"],["u","v","w","x","y","z","a","b","c","d","e","f"],["g","h","i","j","k","l","m","n","o","p","q","r"],["s","t","u","v","w","x","y","z","a","b","c","d"],["e","f","g","h","i","j","k","l","m","n","o","p"],["q","r","s","t","u","v","w","x","y","z","a","b"],["c","d","e","f","g","h","i","j","k","l","m","n"]],"words":["abcdefghij","klmnopqrst","uvwxyzabcd","efghijklmn","opqrstuvwx","yzabcdefgh","ijklmnopqr","stuvwxyzab","cdefghijkl","mnopqrstuv","wxyzabcdef","ghijklmnop","rstuvwxyz","defghijklm","nopqrstuvw","xyzabcdefg","hijklmnopq","tuvwxyzabc","efghijklmn","pqrstuvwxy","zabcdefgh","jklmnopqrs","uvwxyzabc","fghijklmn","rstuvwxyza","bcdefghijk","lmnopqrst","vwxyzabcd","ghijklmnop","stuvwxyzab"]}
⏱ Performance - must finish in 2000ms

Large 12x12 board with 30 words of length up to 10 to test performance of trie + DFS pruning approach within 2 seconds.

Practice

(1/5)
1. Given the following code snippet for MapSum, after inserting keys "apple" with value 3 and "app" with value 2, what is the value of node.sum at the trie node corresponding to 'p' (the second character) after the second insert?
easy
A. 3
B. 5
C. 2
D. 0

Solution

  1. Step 1: Trace insert of "apple" with value 3

    Delta = 3 - 0 = 3. Root.sum += 3 -> 3. For each character 'a','p','p','l','e', node.sum += 3. After first insert, node at second 'p' has sum 3.
  2. Step 2: Trace insert of "app" with value 2

    Delta = 2 - 0 = 2. Root.sum += 2 -> 5. For 'a','p','p', node.sum += 2. Node at second 'p' sum was 3, now 3 + 2 = 5.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Sum at second 'p' after both inserts is 5 [OK]
Hint: Sum accumulates delta on each insert per prefix node [OK]
Common Mistakes:
  • Forgetting to add delta on second insert
  • Confusing first and second 'p' nodes
  • Using old value instead of delta
2. You are given an array of integers and multiple queries. Each query provides a number x and a limit m. For each query, you must find the maximum XOR of x with any array element less than or equal to m. Which approach guarantees an optimal solution for large inputs?
easy
A. Sort the array and queries, then use a bitwise trie to insert elements up to the query limit and find max XOR.
B. Use dynamic programming to store XOR results for all subarrays and answer queries in O(1).
C. Use a brute force nested loop checking all elements for each query.
D. Apply a greedy approach by always choosing the element with the highest value less than or equal to m.

Solution

  1. Step 1: Understand problem constraints

    Brute force is too slow for large inputs; DP for subarrays doesn't apply since queries are arbitrary.
  2. Step 2: Recognize the pattern

    Sorting nums and queries allows incremental trie insertion of eligible elements, enabling efficient max XOR queries.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Sorting + trie insertion matches known optimal approach [OK]
Hint: Sort queries and nums, then use bit trie [OK]
Common Mistakes:
  • Thinking brute force is efficient enough
  • Using DP for unrelated subproblems
  • Greedy max element doesn't guarantee max XOR
3. The following code attempts to answer maximum XOR queries with constraints using a bit trie. Which line contains a subtle bug that can cause incorrect results or runtime errors when no nums ≤ m are available?
medium
A. Line: node = node.children[bit]
B. Line: if not node.children[bit]: node.children[bit] = TrieNode()
C. Line: node = self.root
D. Line: if node.children[toggled_bit]:

Solution

  1. Step 1: Identify empty trie scenario

    If no nums ≤ m, trie is empty; node.children[bit] can be None.
  2. Step 2: Check max_xor traversal

    Line assigning node = node.children[bit] assumes child exists, causing runtime error or wrong result.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Must handle empty child case to avoid errors [OK]
Hint: Check for None before descending trie [OK]
Common Mistakes:
  • Ignoring empty trie case
  • Assuming children always exist
  • Not returning -1 when no valid nums
4. Examine the following buggy code snippet for palindrome pairs using Trie + DFS. Which line contains the subtle bug that causes missing pairs involving empty strings?
medium
A. No special handling for empty string in add_word or search
B. Line checking is_palindrome(word[:len(word)-i]) in add_word
C. Line checking if node.index >= 0 and node.index != index in search
D. Line setting node.index = index after insertion

Solution

  1. Step 1: Identify empty string edge case

    Empty string pairs with palindromes require special handling to add pairs involving empty string indices.
  2. Step 2: Check code for empty string handling

    Neither add_word nor search explicitly handle empty string cases, causing missing pairs.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Empty string handling is a known subtle bug [OK]
Hint: Empty string pairs require explicit checks [OK]
Common Mistakes:
  • Assuming palindrome checks cover empty strings
  • Missing empty string special case
  • Confusing index assignments
5. Examine the following buggy code snippet for building the trie and collecting suggestions. Which line contains the subtle bug that can cause incorrect suggestion ordering or runtime errors?
medium
A. Line with 'products.sort()' missing before building trie
B. Line with 'for product in products:' loop
C. Line with 'if len(node.suggestions) < 3:' condition
D. Line with 'if node and ch in node.children:' during search

Solution

  1. Step 1: Identify missing sorting

    The code does not sort products before building the trie, so suggestions are appended in input order, not lex order.
  2. Step 2: Consequences of missing sort

    Without sorting, the suggestions list at each node is not guaranteed to be lexicographically smallest three, violating problem requirements.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Sorting before trie build is essential for correct lex order [OK]
Hint: Always sort products before building trie for lex order [OK]
Common Mistakes:
  • Forgetting to sort products
  • Appending suggestions without limit
  • Not handling missing prefix nodes
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard