Advertisement
jules0707

BoggleSolver.java

May 3rd, 2021 (edited)
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 6.87 KB | None | 0 0
  1. /*
  2. Correctness:  13/13 tests passed
  3. Memory:       3/3 tests passed
  4. Timing:       8/9 tests passed
  5. Aggregate score: 92.78%
  6. [ Compilation: 5%, API: 5%, Style: 0%, Correctness: 60%, Timing: 10%, Memory: 20% ]
  7.  
  8. ////////////////////////////////////////////////////////////////////////////////////
  9.  
  10. Test 2: timing getAllValidWords() for 5.0 seconds using dictionary-yawl.txt
  11.         (must be <= 2x reference solution)
  12.     - reference solution calls per second: 9288.02
  13.     - student   solution calls per second: 4513.83
  14.     - reference / student ratio:           2.06
  15.  
  16. => passed    student <= 10000x reference
  17. => passed    student <=    25x reference
  18. => passed    student <=    10x reference
  19. => passed    student <=     5x reference
  20. => FAILED    student <=     2x reference
  21.  
  22. Total: 8/9 tests passed!
  23. */
  24.  
  25.  
  26. import edu.princeton.cs.algs4.Bag;
  27. import edu.princeton.cs.algs4.In;
  28. import edu.princeton.cs.algs4.StdOut;
  29. import java.util.HashSet;
  30.  
  31. public class BoggleSolver {
  32.  
  33.     private final TrieSET26 trie;
  34.     private int rows;
  35.     private int cols;
  36.     private boolean[] marked;
  37.     private StringBuilder prefix;
  38.     private HashSet<String> validWords;
  39.     private Bag<Integer>[] adj;
  40.  
  41.     // Initializes the data structure using the given array of strings as the dictionary.
  42.     // (You can assume each word in the dictionary contains only the uppercase letters A through Z.)
  43.     public BoggleSolver(String[] dictionary) {
  44.         trie = new TrieSET26();
  45.         for (String w : dictionary) {
  46.             trie.add(w); // Build 26-way trie
  47.         }
  48.     }
  49.  
  50.     // Returns the set of all valid words in the given Boggle board, as an Iterable.
  51.     public Iterable<String> getAllValidWords(BoggleBoard board) {
  52.         cols = board.cols();
  53.         rows = board.rows();
  54.         int n = cols * rows;
  55.         validWords = new HashSet<>(); // all the valid words that can be created from letter at [c][r]
  56.         marked = new boolean[cols * rows]; // if a letter has already been used in this prefix-word only
  57.         prefix = new StringBuilder(); // the prefix used to search words starting with letter located at [i][j]
  58.  
  59.         // Precompute the set of cubes adjacent to each cube
  60.         adj = new Bag[n];
  61.         for (int i = 0; i < cols; i++) { // build the adj array for every positions in board
  62.             for (int j = 0; j < rows; j++) {
  63.                 int k = cols * j + i; // kth position of letter[i][j] in 2D grid starting at 0
  64.                 adj[k] = adj(k);
  65.             }
  66.         }
  67.         for (int cube = 0; cube < n; cube++) { // in board. One new prefix for each starting board letter.
  68.             char letter = getLetter(board, cube);
  69.             append(letter);
  70.             DFS(board, cube);
  71.         }
  72.         return validWords;
  73.     }
  74.  
  75.     // Returns the score of the given word if it is in the dictionary, zero otherwise.
  76.     // (You can assume the word contains only the uppercase letters A through Z.)
  77.     public int scoreOf(String word) {
  78.         return trie.contains(word) ? points(word) : 0;
  79.     }
  80.  
  81. ///////////////////// UTILITIES  /////////////////////
  82.  
  83.     private void DFS(BoggleBoard board, int k) {
  84.         marked[k] = true;
  85.         for (int x : adj[k]) { // for all the adjacent letters
  86.             if (!marked[x]) {
  87.                 char letter = getLetter(board, x);
  88.                 append(letter);
  89.                 String word = prefix.toString();
  90.  
  91.                 if (trie.hasKeysWithPrefix(word)) { // at least one key with prefix word exists in dictionary
  92.                     if (word.length() >= 3) {
  93.                         if (trie.contains(word))
  94.                             validWords.add(word); // found a matched word !! duplicates are skipped as validWords is a HashSet!
  95.                     }
  96.                     DFS(board, x); // keep on searching for longer prefixes
  97.                 } else {
  98.                 /* backtracking optimization: when the current path corresponds to a string that is not
  99.                 a prefix of any word in the dictionary, there is no need to expand the path further. */
  100.                     backTrack(x, letter);
  101.                 }
  102.             }
  103.         }
  104.         char letter = getLetter(board, k);
  105.         backTrack(k, letter);
  106.     }
  107.  
  108.     private Bag<Integer> adj(int c) {
  109.         Bag<Integer> res = new Bag<>();
  110.         int i = c % cols;
  111.         int j = c / cols;
  112.         int n, s, e, w, se, sw, ne, nw;
  113.  
  114.         // north?
  115.         if (j > 0) {
  116.             n = c - cols;
  117.             res.add(n);
  118.         }
  119.         // south?
  120.         if (j < rows - 1) {
  121.             s = c + cols;
  122.             res.add(s);
  123.         }
  124.         // east?
  125.         if (i < cols - 1) {
  126.             e = c + 1;
  127.             res.add(e);
  128.         }
  129.         // west?
  130.         if (i > 0) {
  131.             w = c - 1;
  132.             res.add(w);
  133.         }
  134.         // southeast?
  135.         if (j < rows - 1 && i < cols - 1) {
  136.             se = c + cols + 1;
  137.             res.add(se);
  138.         }
  139.         // southwest?
  140.         if (j < rows - 1 && i > 0) {
  141.             sw = c + cols - 1;
  142.             res.add(sw);
  143.         }
  144.         // northeast?
  145.         if (j > 0 && i < cols - 1) {
  146.             ne = c - cols + 1;
  147.             res.add(ne);
  148.         }
  149.         // northwest?
  150.         if (j > 0 && i > 0) {
  151.             nw = c - cols - 1;
  152.             res.add(nw);
  153.         }
  154.         return res;
  155.     }
  156.  
  157.     private int points(String w) {
  158.         int e = w.length();
  159.         if (e < 3) return 0;
  160.         if (e == 3 || e == 4) return 1;
  161.         if (e == 5) return 2;
  162.         if (e == 6) return 3;
  163.         if (e == 7) return 5;
  164.         else return 11;
  165.     }
  166.  
  167.     private void append(char letter) {
  168.         prefix.append((letter == 'Q') ? "QU" : letter); // construct one letter longer new prefix-word with QU counting as one
  169.     }
  170.  
  171.     private void backTrack(int x, char letter) { // from position x remove letter from prefix
  172.         marked[x] = false; // reset for further search via different path
  173.         prefix.deleteCharAt(prefix.length() - 1); // remove the last char in prefix
  174.         if (letter == 'Q') { // we remove a further char corresponding to the added extra 'U'
  175.             prefix.deleteCharAt(prefix.length() - 1);
  176.         }
  177.     }
  178.  
  179.     private char getLetter(BoggleBoard board, int k) {
  180.         if (rows == 1) return board.getLetter(0, k);
  181.         if (cols == 1) return board.getLetter(k, 0);
  182.            else return board.getLetter(k / cols, k % cols);
  183.     }
  184.  
  185.     public static void main(String[] args) {
  186.         In in = new In(args[0]);
  187.         String[] dictionary = in.readAllStrings();
  188.         BoggleSolver solver = new BoggleSolver(dictionary);
  189.         BoggleBoard board = new BoggleBoard(args[1]);
  190.         int score = 0;
  191.         for (String word : solver.getAllValidWords(board)) {
  192.             StdOut.println(word);
  193.             score += solver.scoreOf(word);
  194.         }
  195.         StdOut.println("Score = " + score);
  196.     }
  197. }
  198.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement