L212. 单词搜索 II

  1. 单词搜索 II
    给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

示例:

输入:
words = [“oath”,“pea”,“eat”,“rain”] and board =
[
[‘o’,‘a’,‘a’,‘n’],
[‘e’,‘t’,‘a’,‘e’],
[‘i’,‘h’,‘k’,‘r’],
[‘i’,‘f’,‘l’,‘v’]
]

输出: [“eat”,“oath”]
说明:
你可以假设所有输入都由小写字母 a-z 组成。

提示:

你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。

1.借助L79的代码

class Solution {
    public List<String> findWords(char[][] board, String[] words) {
        //转化为L79的查找问题
        List<String> list = new ArrayList<>();
        for(String st : words){
            if(exist(board, st)){
                list.add(st);//这里就直接使用79代码
            }
        }
        return list;
    }
    int m, n;
    int mp[][] ={{1, 0}, {-1, 0}, {0, -1}, {0, 1}};
    public boolean exist(char[][] board, String word) {
        m = board.length;
        n = board[0].length;
        if(m == 0) return false;
        boolean flag[][] = new boolean[m][n];
        for(int i = 0; i < m; i++){//对所有的方格点进行遍历
            for(int j = 0; j < n; j++){
                if(dfs(board, word, i, j, flag, 0)) return true;
            }
        }
        return false;
    }
    public boolean dfs(char[][] board, String word, int i, int j, boolean[][] flag, int index){
        if(index == word.length() - 1){//与常规的判断方式有些不同,如果直接写index== word.length,由于下面有好多判断条件,其实走不到dfs
            //比如只有一个字母的时候
            return word.charAt(index) == board[i][j];
        }
        if(board[i][j] == word.charAt(index)){
            //四个方向依次判断
            flag[i][j] = true;//先标记
            for(int k = 0; k < 4; k++){
                int newX = i + mp[k][0];
                int newY = j + mp[k][1];
                if(newX >= 0 && newX < m && newY >= 0 && newY < n && flag[newX][newY] == false){
                    if(dfs(board, word, newX, newY, flag, index + 1)) return true;
                }
            }
            flag[i][j] = false;
        }
        return false;
    }
}

3.遍历过程中判断是否遇到了某个单词,我们可以事先把所有单词存到前缀树中。这样的话,如果当前走的路径不是前缀树的前缀,我们就可以提前结束了。如果是前缀树的中的单词,我们就将其存到结果中。

至于实现的话,我们可以在遍历过程中,将当前路径的单词传进函数,然后判断当前路径构成的单词是否是在前缀树中出现即可。

我们可以将前缀树融合到我们的算法中,递归中去传递前缀树的节点,判断当前节点的孩子是否为 null,如果是 null 说明当前前缀不存在,可以提前结束。如果不是 null,再判断当前节点是否是单词的结尾,如果是结尾直接将当前单词加入。

不能通过,不知道原因

class Trie {
    Node root;
    public Trie(){
        root = new Node();
    }

    public void insert(String word) {
        Node now = root;//每次获取当前的第一个节点
        char ch[] = word.toCharArray();
        int len = ch.length;
        for(int i = 0; i < len; i++){
            if(now.next[ch[i] - 'a'] == null){//没有就新建一个
                now.next[ch[i] - 'a'] = new Node();
            }
            now= now.next[ch[i] - 'a'];//进入下一个节点
        }
        now.word =  word;
    }
}

class Solution {
    public List<String> findWords(char[][] board, String[] words) {
        Trie trie = new Trie();
        List<String> list = new ArrayList<>();
        for(String st : words){//全部加入前缀树
            trie.insert(st);
        }
        boolean flag[][] = new boolean[m][n];
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                dfs(board, i, j, flag, list,trie.root);
                //参数要重新设置,不需要String,只需要与前缀树比较即可
            }
        }
        return list;
    }
    int m, n;
    int[][] mp = {{1, 0},{-1, 0}, {0, 1}, {0, -1}};

    public void dfs( char[][] board, int i, int j, boolean[][] flag, List<String> list, Node node){//注意是Node,不是Trie
        m = board.length;//忘记给m, n赋值
        n = board[0].length;
        if(i >= 0 && i < m && j >= 0 && j < n && flag[i][j] == false && node.next[(board[i][j] - 'a')] != null){

            node = node.next[(board[i][j] - 'a')];
            if(node.word != null){
                //此时已经到达一个单词的结尾
                list.add(node.word);
                node.word = null;//防止重复加入
            }

            flag[i][j] = true;
            for(int k = 0; k < 4; k++){
                int newx = i + mp[k][0];
                int newy = j + mp[k][1];
                dfs(board, newx, newy, flag, list, node);
            }
            flag[i][j] = false;
        }

    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值