LintCode 单词搜索Ⅱ 字典树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LintCode 单词搜索Ⅱ 字典树相关的知识,希望对你有一定的参考价值。

今天做了道有意思的题目,题目要解出来不难,但看到他的提示

技术分享

 

发现这道题我一开始并没有用到字典树

 

然后就使用字典树+DFS写了一遍,也算是巩固下字典树的相关知识

 

题目:原题地址

 

给出一个由小写字母组成的矩阵和一个字典。找出所有同时在字典和矩阵中出现的单词。一个单词可以从矩阵中的任意位置开始,可以向左/右/上/下四个相邻方向移动。

样例

给出矩阵:

doaf
agai
dcan

和字典:

{"dog", "dad", "dgdg", "can", "again"}
 
返回 {"dog", "dad", "can", "again"}
 
挑战 

使用单词查找树来实现你的算法

 

解题思路:

先对给的字典建立一颗字典树,然后使用DFS在给的矩阵内搜索字典树,相关注释现在了代码里。

下面贴代码:

package ww;

import java.util.ArrayList;
import java.util.Arrays;

import org.junit.Test;

public class TestDC {

    @Test
    //测试用例
    //输出:[dog, dad, again, can]
    public void test() {
        char[][] board = { { ‘d‘, ‘o‘, ‘a‘, ‘f‘ }, { ‘a‘, ‘g‘, ‘a‘, ‘i‘ }, { ‘d‘, ‘c‘, ‘a‘, ‘n‘ } };
        ArrayList<String> list = new ArrayList<String>();
        String[] tem = { "dog", "dad", "dgdg", "can", "again" };
        for (String tt : tem) {
            list.add(tt);
        }
        ArrayList<String> wordSearchII = wordSearchII(board, list);
        System.out.println(wordSearchII);
    }

    
    int MAX_N = 1000000;//字典树最大深度
    int MAX_C = 26;//表示26个小写字母
    int tot = 0;//用于记录位置
    String[] ch;//用来标记结尾的字母所对应的单词
    int[][] cnt;//用来表示字典树

    //初始化字典树
    public void init() {
        ch = new String[MAX_N];
        cnt = new int[MAX_N][];

        Arrays.fill(ch, null);
        Arrays.fill(cnt, null);
    }

    //构建字典树
    public void insert(String str) {
        int p = 0;
        for (char ch : str.toCharArray()) {
            if (cnt[p] == null) {
                cnt[p] = new int[MAX_C];
                Arrays.fill(cnt[p], -1);
            }

            /**
             * 表示该单词下一个字母应对应的位置
             */
            if (cnt[p][ch - ‘a‘] == -1) {
                cnt[p][ch - ‘a‘] = ++tot;
            }
            p = cnt[p][ch - ‘a‘];
        }
        //表示这个单词插入玩成,在字典树对应的最后一个字母上,标记这个单词,以便查找
        if (ch[p] == null) {
            ch[p] = str;
        }
    }

//支持1.8的话,使用下面的Stream去重。不支持的话使用HashSet去重    
//原理相同
//      public void dfsFind(char[][] board, boolean[][] visited, int row, int col, int p, HashSet<String> list) {
//        if (ch[p] != null) {
//            list.add(ch[p]);
//        }
//        if (row >= 0 && row < board.length && col >= 0 && col < board[0].length && visited[row][col] == false
//                && (cnt[p] != null) && (p = cnt[p][board[row][col] - ‘a‘]) != -1) {
//            visited[row][col] = true;
//
//            dfsFind(board, visited, row - 1, col, p, list);
//            dfsFind(board, visited, row, col + 1, p, list);
//            dfsFind(board, visited, row + 1, col, p, list);
//            dfsFind(board, visited, row, col - 1, p, list);
//            visited[row][col] = false;
//
//        }
//
//    }
//
//    public ArrayList<String> wordSearchII(char[][] board, ArrayList<String> words) {
//        init();
//        for (String str : words) {
//            insert(str);
//        }
//        boolean[][] visited = new boolean[board.length][board[0].length];
//        HashSet<String> list = new HashSet<String>();
//        for (int i = 0; i < board.length; i++) {
//            for (int j = 0; j < board[0].length; j++) {
//                dfsFind(board, visited, i, j, 0, list);
//            }
//        }
//        ArrayList<String> rl = new ArrayList<String>();
//        Iterator<String> iterator = list.iterator();
//        while (iterator.hasNext()) {
//            rl.add(iterator.next());
//        }
//        return rl;
//    }
     

    //dfs搜索寻找单词
    public void dfsFind(char[][] board, boolean[][] visited, int row, int col, int p, ArrayList<String> list) {
        //找到了,加入list
        if (ch[p] != null) {
            list.add(ch[p]);
        }
        //依次向4个方向搜索
        if (row >= 0 && row < board.length && col >= 0 && col < board[0].length && visited[row][col] == false
                && (cnt[p] != null) && (p = cnt[p][board[row][col] - ‘a‘]) != -1) {
            visited[row][col] = true;

            dfsFind(board, visited, row - 1, col, p, list);
            dfsFind(board, visited, row, col + 1, p, list);
            dfsFind(board, visited, row + 1, col, p, list);
            dfsFind(board, visited, row, col - 1, p, list);
            visited[row][col] = false;

        }

    }

    public ArrayList<String> wordSearchII(char[][] board, ArrayList<String> words) {
        init();//字典树的初始化
        //构建字典树
        for (String str : words) {
            insert(str);
        }
        //用于标记以走过的路程
        boolean[][] visited = new boolean[board.length][board[0].length];
        ArrayList<String> list = new ArrayList<String>();
        //搜索
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                dfsFind(board, visited, i, j, 0, list);
            }
        }
        //去重
        ArrayList<String> rl = new ArrayList<String>();
        list.stream().distinct().forEach(rl::add);
        return rl;
    }
}

 



以上是关于LintCode 单词搜索Ⅱ 字典树的主要内容,如果未能解决你的问题,请参考以下文章

leetcode打卡--数据结构设计-添加于搜索单词(字典树--Trie)

搜索二叉树应用——简单字典实现

Trie树详解(转)

lintcode 单词接龙II

单词拆分II

LeetCode 230. 二叉搜索树中第K小的元素 / 476. 数字的补数 / 211. 添加与搜索单词 - 数据结构设计(字典树)