Word Search Problem with Trie Solution

Given a 2D board and a list of words from the dictionary, find all words in the board.java

Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.算法

For example,
Given words = ["oath","pea","eat","rain"] and board =數組

[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]

Return ["eat","oath"].數據結構


經過檢查每個入口( 0 <= i < n | n = board.height, 0 <= j < m|board.width)開始的(經過上下左右)相連的字符串,是否和給定的字符串匹配,能夠在O(n * m * max(length of word) * count(words))的時間裏完成;可是,當咱們檢查某個連在一塊兒的字符串的時候,若是該字符串不是任何一個給定字符串的前綴,那麼就能夠提早結束,從而提高效率;快速檢查某個字符串是一組字符串(某個字符串)前綴的數據結構是Trie;測試

class TrieNode {
    private TrieNode[] children;
    private boolean end = false;
    // Initialize your data structure here.
    public TrieNode() {
        this.children = new TrieNode[26];
    }

    public void insert(char[] words, int i) {
        if (i >= words.length - 1) {
            this.end = true;
            return;
        }

        int j = i + 1;
        char nxt = words[j];
        TrieNode child = children[nxt - 'a'];
        if (child == null) {
            child = new TrieNode();
            children[nxt - 'a'] = child;
        }
        child.insert(words, j);
    }

    public boolean startsWith(char[] words, int i) {
        if(i >= words.length - 1) {
            return true;
        }
        int j = i + 1;
        char nxt = words[j];
        TrieNode child = children[nxt - 'a'];
        if(child == null) {
            return false;
        }
        return child.startsWith(words, j);
    }

    public boolean search(char[] words, int i) {
        if(i >= words.length - 1) {
            return this.end;
        }
        int j = i + 1;
        char nxt = words[j];
        TrieNode child = children[nxt - 'a'];
        if(child == null) {
            return false;
        }
        return child.search(words, j);
    }
}

public class Trie {
    private TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    // Inserts a word into the trie.
    public void insert(String word) {
        root.insert(word.toCharArray(), -1);
    }

    // Returns if the word is in the trie.
    public boolean search(String word) {
        return root.search(word.toCharArray(), -1);
    }

    // Returns if there is any word in the trie
    // that starts with the given prefix.
    public boolean startsWith(String prefix) {
        return root.startsWith(prefix.toCharArray(), -1);
    }

    public static void main(String[] args) {
        Trie trie = new Trie();
        trie.insert("ab");
        System.out.println(trie.search("a"));
        System.out.println(trie.startsWith("a"));
    }
}

有了trie,再經過深度優先算法;this

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by senyuanwang on 15/5/19.
 */
public class Solution {

    static int[] dx = new int[]{-1, 0, 0, 1};
    static int[] dy = new int[]{0, -1, 1, 0};

    public static void visit(char[][] board, boolean[][] checked, int i, int j, Trie trie, String path, Set<String> result) {
        if (trie.search(path)) {
            result.add(path);
//            return;
        }

        if (!trie.startsWith(path)) {
            return;
        }

        for (int k = 0; k < 4; k++) {
            int x = dx[k] + i;
            int y = dy[k] + j;
            if (x >= 0 && x < board.length && y >= 0 && y < board[0].length && !checked[x][y]) {
                checked[x][y] = true;
                visit(board, checked, x, y, trie, path + board[x][y], result);
                checked[x][y] = false;
            }
        }
    }

    public static List<String> findWords(char[][] board, String[] words) {
        Trie trie = new Trie();
        for (String word : words) {
            trie.insert(word);
        }

        boolean[][] checked = new boolean[board.length][board[0].length];
        Set<String> result = new HashSet<String>();
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                checked[i][j] = true;
                visit(board, checked, i, j, trie, "" + board[i][j], result);
                checked[i][j] = false;
            }
        }

        List<String> list = new ArrayList<String>(result.size());
        for (String str : result) {
            list.add(str);
        }
        return list;
    }

    public static void main(String[] args) {
        char[][] board = {
                {'a', 'a'}, {'a', 'b'}};

        String[] words = {"aba", "baa", "bab", "aaab", "aaa", "aaaa", "aaba"};
        System.out.println(findWords(board, words));
    }
}

這裏須要注意的一點是,當檢查到生成的字符串知足要求(即與數組中的某個字符串匹配)時,不能結束查找,不然會丟掉結果。好比在上面用於測試的例子中, aaa和aaab都符合條件,aaa將會被先找到,若是返回了,aaab將會被丟掉;spa

相關文章
相關標籤/搜索