给定一个字符类型的二维数组board,和一个字符串组成的列表words。返回words哪些单词可以被走出来。

问题描述:

        给定一个字符类型的二维数组board,和一个字符串组成的列表words。可以从board任何位置出发,每一步可以走向上、下、左、右,四个方向,但是一条路径已经走过的位置,不能重复走。返回words哪些单词可以被走出来。
例子
        board = [
                        ['o','a','a','n'],
                        ['e','t','a','e'],
                        ['i','h','k','r'],
                        ['i','f','l','v']
                     ]
        words = ["oath","pea","eat","rain"]
输出:["eat","oath"]

代码:

    public static class TrieNode {
        public TrieNode[] nexts;
        public int pass;
        public int end;

        public TrieNode() {
            nexts = new TrieNode[26];
            pass = 0;
            end = 0;
        }
    }

    public static void fillWord(TrieNode node, String word) {
        node.pass++;
        char[] chs = word.toCharArray();
        int index = 0;
        for (int i = 0; i < chs.length; i++) {
            index = chs[i] - 'a';
            if (node.nexts[index] == null) {
                node.nexts[index] = new TrieNode();
            }
            node = node.nexts[index];
            node.pass++;
        }
        node.end++;
    }

    public static String generatePath(LinkedList<Character> path) {
        char[] str = new char[path.size()];
        int index = 0;
        for (Character cha : path) {
            str[index++] = cha;
        }
        return String.valueOf(str);
    }

    public static List<String> findWords(char[][] board, String[] words) {
        TrieNode head = new TrieNode();//前缀树最顶端的头
        HashSet<String> set = new HashSet<>();
        for (String word : words) {
            if (!set.contains(word)) {
                fillWord(head, word);
                set.add(word);
            }
        }

        //答案
        List<String> res = new ArrayList<>();
        //沿途走过的字符,收集起来存在path中
        LinkedList<Character> path = new LinkedList<>();
        for (int row = 0; row < board.length; row++) {
            for (int col = 0; col < board[0].length; col++) {
                //枚举board中的所有位置
                //每一个位置出发的情况下,答案都收集
                process(board, row, col, path, head, res);
            }
        }
        return res;
    }

    //从board[row][col]位置的字符出发
    //之前的路径上,走过的字符记录在path中
    //cur还没有登上,有待检查能不能登上去的前缀树的节点
    //如果找到words中的某个str,就记录在res中
    //返回值从row,col出发,一共找到多少个str
    public static int process(char[][] board, int row, int col, LinkedList<Character> path, TrieNode cur, List<String> res) {
        char cha = board[row][col];
        if (cha == 0) {//这个row  col位置是之前走过的位置
            return 0;
        }

        //(row,col)不是回头路
        int index = cha - 'a';
        //如果没路,或者这条路上最终的字符串之前加入过结果中
        if (cur.nexts[index] == null || cur.nexts[index].pass == 0) {
            return 0;
        }
        //没有走回头路,且能登上去
        cur = cur.nexts[index];
        path.addLast(cha);//当前位置的字符添加到路径里去
        int fix = 0;//从row和col位置出发,后序一共搞定多少答案
        //当我来到row col位置,如果决定不往后走了。是不是已经搞定某个字符串了
        if (cur.end > 0) {
            res.add(generatePath(path));
            cur.end--;
            fix++;
        }


        //往上下左右四个方向尝试
        board[row][col] = 0;
        if (row > 0) {
            fix += process(board, row - 1, col, path, cur, res);
        }
        if (row < board.length - 1) {
            fix += process(board, row + 1, col, path, cur, res);
        }
        if (col > 0) {
            fix += process(board, row, col - 1, path, cur, res);
        }
        if (col < board[0].length - 1) {
            fix += process(board, row, col + 1, path, cur, res);
        }
        board[row][col] = cha;
        path.pollLast();
        cur.pass -= fix;
        return fix;
    }

    public static void main(String[] args) {
        char[][] board = {
                {'o','a','a','n'},
                {'e','t','a','e'},
                {'i','h','k','r'},
                {'i','f','l','v'}
        };
        String[] words = {"oath","pea","eat","rain"};
        List<String> ans = findWords(board,words);
        System.out.println(ans);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值