普林斯顿算法课Part2第四周作业_Boggle

作业地址:http://coursera.cs.princeton.edu/algs4/assignments/boggle.html

作业难点:

1、如何保证求解速度,满分要求是求解速度 >= 0.5 * 参考速度,约在5000次/5s。

  1)最直观的算法思想:要明确查找单词即为对一个游戏板(board)上的一个顶点向8个方向进行深度优先遍历,在遍历过程中查找单词是否在词典中,将在词典中的单词记录保存下来。为顺利找出所有满足条件的单词,可以使用广度、深度优先遍历该顶点。重复遍历完所有顶点即可找出在词典中的所有单词。

  2)根据算法思想构建数据结构:游戏板-board[][]一个二维数组,构建词典使用教材提及的TST(三叉单词查找树)或者Trie(单词查找树),保存已找出的单词(因为按题目要求重复单词只保留一个)使用HashSet,遍历方法采用dfs(深度优先搜索)方法。

  3)根据dfs原理构建算法求解,使用marked[][]标记已访问的顶点,使用TST构建词典,求解速度约在2500次/5s,需要优化。

  4)为避免回溯过程中重复查找单词树,为TST新增一个hasPrefix(String key)函数(查找单词树中是否包含key前缀),返回TST的Node类型:root——未查找到,非root——查找到。因为返回的是Node,所以每次只需查找Node以后的枝叶即可,key也即board[i][j]的字母即可。此时,求解速度约在3500次/5s,需要优化。

  5)弃用TST,改用Trie构建词典,修改hasPrefix()函数为getNext(String key)函数,此时求解速度上次到6500次/5s,可以满分,离参考值还有一段距离。

  6)因为查找的过程中存在重复单词,所以在开始的时候使用HashSet来保存找到的单词,存在查找重复单词并将其重复插入的情况。为避免对重复单词进行多次处理,设置处理过的单词的val值为-1,并记录该节点的位置,将其保存下来,在处理的最后对节点的val进行恢复。没有了重复单词,也就不需要HashSet来保存查找到的单词,使用简单的链表来保存即可,保存单词的速度更快。此时求解速度可以上升到10000次/5s。

容易扣分点:

同作业难点。

部分代码:

1、数据结构:

    private Trie dict;
    private String[][] gameStr;
    private Bag<String> words;       // found words
    private Bag<Trie.Node> nodes;    // nodes of found words
    private static class Trie {
        private static int R = 26;   // Radix, English alphabet
        private static final int OFFSET = 'A'; 
public Node root; class Node { int val; Node[] next = new Node[R]; }
}

2、getAllValidWords(BoggleBoard board):

    public Iterable<String> getAllValidWords(BoggleBoard board) {
        words = new Bag<String>();
        nodes = new Bag<Trie.Node>();
        int col = board.cols(), row = board.rows();  
        boolean[][] marked = new boolean[row][col];
        gameStr = new String[row][col];  
        for (int i = 0; i < row; i++)
            for (int j = 0; j < col; j++) 
            gameStr[i][j] = representQ(i, j, board);
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {    
                Trie.Node pNode = dict.getNext(dict.root, gameStr[i][j]);
                if (pNode != null)
                 dfs(board, marked, i, j, pNode, gameStr[i][j]);
            }
        }
        for (Trie.Node n : nodes)
            n.val = 1;
        return words;
    }
    private void dfs(BoggleBoard board, boolean[][] marked,
                     int x, int y, Trie.Node pNode, String preStr) {  
        marked[x][y] = true;  
        String curStr;
        int xNeighbor, yNeighbor;
        Trie.Node queryNode;
        if (pNode.val == 1 && preStr.length() > 2) {
            words.add(preStr);
            nodes.add(pNode);
            pNode.val = -1;
        }
        for (int i = 0; i < XDELTA.length; i++) {
            xNeighbor = x + XDELTA[i];
            yNeighbor = y + YDELTA[i];
            if (validPos(xNeighbor, yNeighbor, board)
                    && !marked[xNeighbor][yNeighbor]) {
                queryNode = dict.getNext(pNode, gameStr[xNeighbor][yNeighbor]);
                if (queryNode != null) {
                    curStr = preStr + gameStr[xNeighbor][yNeighbor];
                    dfs(board, marked, xNeighbor, yNeighbor, queryNode, curStr);
                }
            }
        }
        marked[x][y] = false;
    }
View Code
原文地址:https://www.cnblogs.com/notTao/p/6389629.html