Algorithms

The Boggle Board problem

7 months, 2 weeks ago ; 105 views
Share this

The Boggle Board problem

The Boggle Board problem can be expressed as follows:

Given a Boggle board consisting of n×m cells filled with characters and a list of words, the task is to find all valid words on the board. A valid word can be formed by following a sequence of adjacent letters on the board, where "adjacent" means horizontally, vertically, or diagonally neighboring cells, and the word exists in the provided list of words.

The solution typically involves constructing a Trie data structure to efficiently search for words and performing a depth-first search (DFS) on the board to explore all possible paths. During the DFS traversal, I check if the sequence of letters encountered forms a valid word by querying the Trie. If a valid word is found, I add it to the list of valid words.

The problem requires careful handling of visited cells on the board to avoid revisiting the same cell in the same path. Optimizations such as early termination of DFS, when no words can be formed with the current prefix, can improve performance.

The problem output is a list of all valid words on the board, which I am returning as the solution.

Boggle Board Solution

def boggle_board(board, words):
    """
    Find valid words on the boggle board.

    Args:
        board (List[List[str]]): 2D grid representing the boggle board.
        words (List[str]): List of words to search for on the board.

    Returns:
        List[str]: List of valid words found on the board.
    """

    # Create a Trie data structure and add all words to it.
    trie = Trie()
    for word in words:
        trie.add(word)

    # Initialize a dictionary to store the final valid words found on the board.
    finalWords = {}

    # Initialize a 2D grid to keep track of visited cells on the board.
    visited = [[False for letter in row] for row in board]

    # Iterate through each cell on the board.
    for i in range(len(board)):
        for j in range(len(board[i])):
            # Explore the board starting from the current cell and search for valid words.
            explore(i, j, board, trie.root, visited, finalWords)

    # Return the list of valid words found on the board.
    return list(finalWords.keys())


def explore(i, j, board, trieNode, visited, finalWords):
    """
    Explore the board recursively to find valid words starting from the cell (i, j).

    Args:
        i (int): Row index of the current cell.
        j (int): Column index of the current cell.
        board (List[List[str]]): 2D grid representing the board.
        trieNode (dict): Current node in the trie representing the prefix of words.
        visited (List[List[bool]]): 2D grid representing visited cells on the board.
        finalWords (dict): Dictionary to store final words found on the board.

    Returns:
        None
    """

    # If the cell has already been visited, return.
    if visited[i][j]:
        return

    # Get the letter at the current cell.
    letter = board[i][j]

    # If the letter is not in the trie node, return.
    if letter not in trieNode:
        return

    # Mark the current cell as visited.
    visited[i][j] = True

    # Move to the next node in the trie.
    trieNode = trieNode[letter]

    # If the end symbol '*' is found in the trie node, add the corresponding word to finalWords.
    if "*" in trieNode:
        finalWords[trieNode["*"]] = True

    # Get neighboring cells of the current cell.
    neighbors = get_neighbors(i, j, board)

    # Recursively explore each neighboring cell.
    for neighbor in neighbors:
        explore(neighbor[0], neighbor[1], board, trieNode, visited, finalWords)

    # Mark the current cell as unvisited after exploring its neighbors.
    visited[i][j] = False

def get_neighbors(i, j, board):
    """
    Get the neighbors of a cell (i, j) on the board.

    Args:
        i (int): Row index of the cell.
        j (int): Column index of the cell.
        board (List[List[str]]): 2D grid representing the board.

    Returns:
        List[List[int]]: List of coordinates of neighboring cells.
    """

    # Initialize an empty list to store the neighbors.
    neighbors = []

    # Check if the cell has a neighbor to the top-left.
    if i > 0 and j > 0:
        neighbors.append([i - 1, j -1])

    # Check if the cell has a neighbor to the top-right.
    if i > 0 and j < len(board[0]) -1:
        neighbors.append([i - 1, j + 1])

    # Check if the cell has a neighbor to the bottom-right.
    if i < len(board) -1 and j < len(board[0]) -1:
        neighbors.append([i + 1, j + 1])

    # Check if the cell has a neighbor to the bottom-left.
    if i < len(board) -1 and j > 0:
        neighbors.append([i + 1, j - 1])

    # Check if the cell has a neighbor to the top.
    if i > 0:
        neighbors.append([i - 1, j])

    # Check if the cell has a neighbor to the bottom.
    if i < len(board) -1:
        neighbors.append([i + 1, j])

    # Check if the cell has a neighbor to the left.
    if j > 0:
        neighbors.append([i, j - 1])

    # Check if the cell has a neighbor to the right.
    if j < len(board[0]) -1:
        neighbors.append([i, j + 1])

    # Return the list of neighboring cell coordinates.
    return neighbors

class Trie:
    """
    Trie data structure implementation for efficient prefix-based searching.
    """

    def __init__(self):
        """
        Initialize a Trie object with an empty root node.
        """
        self.root = {}
        self.endSymbol = "*"

    def add(self, word):
        """
        Add a word to the Trie.

        Args:
            word (str): The word to be added to the Trie.
        """
        current = self.root
        for letter in word:
            # If the letter is not already present in the current node's children,
            # create a new node for it.
            if letter not in current:
                current[letter] = {}
            # Move to the next node corresponding to the letter.
            current = current[letter]
        # Mark the end of the word by adding the end symbol as a key in the current node.
        # This indicates that the word ends at this node.
        current[self.endSymbol] = word

 

Code Walkthrough

I will explain my thought process on implementing the different functions in the code above.

boggle_board function

 The boggle_board function takes a boggle board (board) and a list of words (words) as input and returns a list of valid words found on the board. Here's a list of the key things happening in this function.

  •     It creates a Trie data structure (trie) and adds all words using the add method.
  •     It initializes a dictionary (finalWords) to store the final valid words on the board.
  •     It initializes a 2D grid (visited) to keep track of visited cells on the board.
  •     It iterates through each cell on the board and calls the explore function to search for valid words starting from that cell.
  •     After exploring all cells, it returns the list of valid words on the board.

 

explore function

  • The explore function recursively explores the board starting from the cell (i, j).
  • It checks if the current cell has already been visited and if the letter at the cell exists in the current trie node, and if the end symbol '*' exists in the trie node to indicate a valid word.
  • If a valid word is found, it is added to the finalWords dictionary.
  • The function then recursively explores the neighboring cells of the current cell.
  • After exploring all neighbors, the current cell is marked as unvisited, allowing other paths to explore it again.

get_neighbors function

  • We define a function get_neighbors that takes the row index i, column index j, and the board as input.
  • We initialize an empty list(neighbors) to store the neighboring cell coordinates.
  • We check each direction around the cell (i, j) to see if there are neighboring cells, and if so, we append their coordinates to the neighbors list.
  • Finally, we return the list of neighboring cell coordinates.

Unit Test

board=[
        ['t', 'h', 'i', 's', 'i', 's', 'a'],
        ['s', 'i', 'm', 'p', 'l', 'e', 'x'],
        ['b', 'x', 'x', 'x', 'x', 'e', 'b'],
        ['x', 'o', 'g', 'g', 'l', 'x', 'o'],
        ['x', 'x', 'x', 'D', 'T', 'r', 'a'],
        ['R', 'E', 'P', 'E', 'A', 'd', 'x'],
        ['x', 'x', 'x', 'x', 'x', 'x', 'x'],
        ['N', 'O', 'T', 'R', 'E', '-', 'P'],
        ['x', 'x', 'D', 'E', 'T', 'A', 'E']
    ]
words =['this','is', 'no','a','simple','boggle','board''test','REPEATED','NOTRE-PEATED']


import unittest 
class BoggleBoardTest(unittest.TestCase):

    def test_boggle_board(self):
        self.assertListEqual(boggle_board(board, words), ['this', 'is', 'simple', 'a', 'boggle', 'NOTRE-PEATED'])

    def test_empty_list(self):
        self.assertNotEqual(boggle_board(board, words), [])

if __name__ =="__main__":
    unittest.main()

Time & Space Complexity

Time Complexity

    Trie Construction

    Constructing the Trie from the given list of words has a time complexity of

    O(w⋅s), where w is the number of words, and s is the length of the longest word.

    Exploring the Board

    We iterate through each cell of the board, and for each cell, we perform a depth-first search (DFS) to explore its neighboring cells.

   In the worst-case scenario, each DFS might explore up to 8^s cells, where s is the length of the longest word in the Trie.
    Therefore, the time complexity for exploring the board is O(n⋅m⋅8^s).

    Overall Time Complexity

    The overall time complexity is dominated by constructing the Trie (O(w⋅s)) and exploring the board (O(n⋅m⋅8^s)). Therefore, the overall time complexity is O(w⋅s+n⋅m⋅8^s).

Space Complexity

    Trie

   Constructing the Trie from the given list of words requires space to store the nodes.

    In the worst case, if all words are unique and have no common prefixes, the space complexity of
    the Trie would be O(w⋅s), where w is the number of words, and s is the length of the longest word.

    Visited Array

    We use a 2D array to keep track of visited cells on the board. The space complexity of this array is O(n⋅m), where n represents the width while m refers to the height of the board.

    Final Words Dictionary

  We use a dictionary to store the final valid words on the board.

  In the worst case, if all words in the Trie are present on the board, the space complexity would be O(w⋅s).

   Overall Space Complexity

    The overall space complexity is dominated by the space required for the Trie, the visited array, and the final words dictionary. Therefore, the overall space complexity is O(w⋅s+n⋅m).

 

 

Become a member
Get the latest news right in your inbox. We never spam!

Mike Hodges at April 6, 2024, 4:14 p.m.

Hi there, My name is Mike from Monkey Digital, Allow me to present to you a lifetime revenue opportunity of 35% That's right, you can earn 35% of every order made by your affiliate for life. Simply register with us, generate your affiliate links, and incorporate them on your website, and you are done. It takes only 5 minutes to set up everything, and the payouts are sent each month. Click here to enroll with us today: https://www.monkeydigital.org/affiliate-dashboard/ Think about it, Every website owner requires the use of search engine optimization (SEO) for their website. This endeavor holds significant potential for both parties involved. Thanks and regards Mike Hodges Monkey Digital

Mike Calhoun at April 3, 2024, 9:09 a.m.

Hi there, I have reviewed your domain in MOZ and have observed that you may benefit from an increase in authority. Our solution guarantees you a high-quality domain authority score within a period of three months. This will increase your organic visibility and strengthen your website authority, thus making it stronger against Google updates. Check out our deals for more details. https://www.monkeydigital.co/domain-authority-plan/ NEW: Ahrefs Domain Rating https://www.monkeydigital.co/ahrefs-seo/ Thanks and regards Mike Calhoun

Mike Forster at April 2, 2024, 8:44 a.m.

This service is perfect for boosting your local business' visibility on the map in a specific location. We provide Google Maps listing management, optimization, and promotion services that cover everything needed to rank in the Google 3-Pack. More info: https://www.speed-seo.net/ranking-in-the-maps-means-sales/ Thanks and Regards Mike Forster PS: Want a ONE-TIME comprehensive local plan that covers everything? https://www.speed-seo.net/product/local-seo-bundle/

Mike Jackson at March 30, 2024, 12:52 a.m.

Hello This is Mike Jackson Let me introduce to you our latest research results from our constant SEO feedbacks that we have from our plans: https://www.strictlydigital.net/product/semrush-backlinks/ The new Semrush Backlinks, which will make your pythonhaven.com SEO trend have an immediate push. The method is actually very simple, we are building links from domains that have a high number of keywords ranking for them.  Forget about the SEO metrics or any other factors that so many tools try to teach you that is good. The most valuable link is the one that comes from a website that has a healthy trend and lots of ranking keywords. We thought about that, so we have built this plan for you Check in detail here: https://www.strictlydigital.net/product/semrush-backlinks/ Cheap and effective Try it anytime soon Regards Mike Jackson mike@strictlydigital.net

PillsHoaky at March 28, 2024, 10:18 p.m.

TruePills, No prescription needed, Buy pills without restrictions. Money Back Guaranteed 30-day refunds. Trial ED Pack consists of the following ED drugs: Viagra Active Ingredient: Sildenafil 100mg 5 pills Cialis 20mg 5 pills Levitra 20mg 5 pills https://cutt.ly/7wC5m1Id http://alt1.toolbarqueries.google.ba/url?q=https://true-pill.top/ http://autodiscover.gazpromenergosbyt.ru/bitrix/redirect.php?goto=https://true-pill.top/ https://www.piccoletrasgressioni.it/geolocation_circuit.asp?circuitog=top&sitog=true-pill.top&nazioneg=IT&tipog=generico http://marble-web.net/denno/mt4i.cgi?id=4&mode=redirect&no=26&ref_eid=906&url=http%3a%2f%2ftrue-pill.top http://metro.faramedia.ru/bitrix/rk.php?goto=https://true-pill.top/ Relyomycin Clindana Clindabuc Rexetin Eritrocap Dexanorm Depine Endoxana Flutarzole Panpot Medocel Gramokil Lexis Exostrept Stada k Laxin Viscard Tolerade Valporal Gabator Jasminellecontinu Llanol Levoxyl Risedon Beahexol Estreva Amvasc Omelind Prid Sitinir Cetam Norveta Lixidol Ethiferan Vasocard Vascord Magnaspor Geavir Acicvir Nufex beta

Mike Pass at March 20, 2024, 4:14 p.m.

Greetings I have just took an in depth look on your pythonhaven.com for the ranking keywords and saw that your website could use a push. We will increase your ranks organically and safely, using only state of the art AI and whitehat methods, while providing monthly reports and outstanding support. More info: https://www.digital-x-press.com/unbeatable-seo/ Regards Mike Pass Digital X SEO Experts

Daniel at March 11, 2024, 2:02 p.m.

Hi there, Come over to our agency with all your digital marketing activities, and we will redo your website absolutely free of charge. This is a tremendous opportunity to work with a real agency with over 14 years of experience in digital marketing. Get in touch with us for our portfolio and offer details. We'll take good care of you. Let me know. Daniel Phone: +1 (586) 372-8384 Whatsapp: +3 (736) 009-2931 Telegram: awesomeagency

Dolahaun at Feb. 22, 2024, 8:53 p.m.

Hello, dear friends! Are you on the lookout for a dependable and budget-friendly hosting provider for your website or online venture? If so, I've got just the thing for you! I've curated a dedicated page on my website where I share my firsthand recommendations for the top-notch hosting providers available in the market. On this page, you'll discover a diverse array of hosting services catering to various needs, including VDS, VPS, dedicated, and even bulletproof hosting. Whether you're in need of straightforward hosting for your blog, robust hosting for your e-commerce platform, or secure hosting for your sensitive data, rest assured, you'll find the perfect match for your requirements on my page. Don't let this opportunity slip away! Head over to my page now and select the ideal hosting provider to propel your online endeavors to new heights! https://stash.surge.sh/posts/info-hosting-recomendations/

Read next

Island Perimeter

&nbsp;This solution seeks to find the perimeter of an island in a grid.&nbsp; The problem considers a grid where each cell represents land (1) or … Read More

Kibsoft 3 months, 3 weeks ago . 76 views

Pacific Atlantic Waterflow

3 months, 3 weeks ago . 82 views