5

I enrolled in the Algorithms, Part II course on Coursera, and one of the assignments is to solve the Boggle game: http://coursera.cs.princeton.edu/algs4/assignments/boggle.html

The honor code requires that I don't publicly post the solution, so here's the pseudocode of the basic algorithm instead.

visit:
  word <- board[i][j]
  start <- dictionary.match(word, start)
  if start is not null
      visited[i][j] <- true
      word <- prefix + word
      if word is longer than min required length 
          words <- words + word

      for (x, y) ∊ adj(i, j)
          if not visited(x, y)
            visit (x, y)

  visited[i][j] <- false

The dictionary is implemented using a Trie.

The above code works, and I passed the assignment, but then I came across this blog post that claims a faster solution using dynamic programming:

It turns out, we can use a nifty dynamic programming technique to quickly check whether a word (from the dictionary in this case) can be constructed from the board or not!

Here is core point of the dynamic programming idea:

For a word of length k to be found (end location) at the [i, j]-th location of the board, the k-1'th letter of that word must be located in one of the adjacent cells of [i, j].

The base case is k = 1.

A letter of length 1 will be found (end location) in the [i, j]-th cell of the board of the only letter in the word matches the letter in the [i, j]-th location of the board.

Once our dynamic programming table is populated with the base case, we can build on top of that for any word of length k, k > 1.

Unfortunately, the author did a poor job of explaining, and I'm not able to follow his solution. I'd like to though, and hoping someone here could explain it to me.

P.S.:

  1. Not a duplicate of this question, as that one doesn't use DP; please, keep those duplicate-happy fingers in check.

  2. There's sufficient effort demonstrated on my part and not asking anyone to do my homework. I already have a solution of my own. What I'm interested in is learning a better way of solving the problem, if one exists.

Thanks!

braX
  • 11,506
  • 5
  • 20
  • 33
Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
  • 3
    @JimGarrison Actually this question would be off-topic on CodeReview as Psuedocode is not accepted. CodeReview requires the full working code with context. – Summer Jul 12 '18 at 05:15
  • @JimGarrison Since this question contains pseudocode and no real code, it doesn't stand a chance at Code Review. Don't recommend a site if you haven't at least read and understood their [help center](https://codereview.stackexchange.com/help/on-topic). – Mast Jul 12 '18 at 05:50
  • Seems like the dp idea has some flaws, for example, algo first start to populate the dp table with 1 word character, then 2 then 3, but I don't think it can check for case when the character(s) are reused – Pham Trung Jul 12 '18 at 07:07
  • In essence what he tries to do is, for a word **w** of length *k* in the dictionary if the word exists-ends at the position (i,j) of the board, then there exists a path of length k, starting from (i,j) that contains the letters of **w** in reverse order. Although i am not sure about the correctness of his pseudocode, the main idea is based on obtaining a path of length *k*, where all the letters of **w** are matched to adjacent nodes of the path. – ichantz Jul 12 '18 at 08:07
  • In the original link, someone already mentioned `benqiang zhuNovember 14, 2016 at 4:41 PM the 3rd method works if it allows using one character repeatedly as long as not continuously. For example, 'dad' was found if 'da' is on the board. 'lee' was not found if 'le' in on the board.` – Pham Trung Jul 12 '18 at 08:12
  • @PhamTrung The assignment doesn't allow the same grid used twice in a word, neither does the real Boggle game. 'dad' or 'lee' is only possible if 'd' and 'e' were respectively repeated in the boards. – Abhijit Sarkar Jul 12 '18 at 08:17
  • As I say, the dp algo cannot handle that case, it is just wrong. I think the owner of the blog already wrote some C++ code, just try to test it with this case. – Pham Trung Jul 12 '18 at 08:19
  • @PhamTrung I'm not expecting a ready solution, or even a correct one, but simply understand the idea that he (vaguely) lays out. If you figured out what he's saying, don't hold back, post an answer here explaining the idea. Who knows, perhaps we will find the flaw in his reasoning and fix it. – Abhijit Sarkar Jul 12 '18 at 08:26

1 Answers1

2

The idea for the DP (wrong) solution is simple, assuming that we want to check if the word "apple" is existing in the table.

  • Let's create a table dp[k][n][n], with dp[a][x][y]means that whether the prefix of the word with length a could end at cell (x, y).

    [a][p][p]
    [x][x][l]
    [x][x][e]
    

For above table, dp[1][0][0] = true, as the prefix length 1 of apple is a and dp[2][0][1] = true etc.

  • So, how to check if dp[a][x][y] is true? check all of the neighbouring cell of (x,y), and if one of its neighbour has dp[a - 1][][] = true, so dp[a][x][y] also true. For our example, for cell (0,2) , dp[3][0][2] = true, as one of its neighbours, cell (0,1) has dp[2][0][1] = true
  • By default, all dp[0][x][y] = true
  • For any cell (x, y) , if dp[length of word][x][y] = true -> the word exists in the table.

Notice that this solution could not check the case when a character is being used for more than one time.

Like if we need to look for the word apa and with the above table

dp[1][0][0] = true -> dp[2][0][1] = true -> dp[3][0][0] = true
Pham Trung
  • 11,204
  • 2
  • 24
  • 43
  • So, either we need to create the `dp` table for each word, or we need to know the max length of all words from the dictionary, right? – Abhijit Sarkar Jul 12 '18 at 18:09
  • @AbhijitSarkar if you ask about implementation details, that's another question. Using bottom up dp, you can totally just reuse one single `dp[2][n][n]` without affecting time complexity. – Pham Trung Jul 13 '18 at 00:48
  • @Pham Trung, so DP solution won't work here right? As it might consider the same cell character more than once. – tusharRawat Mar 23 '20 at 18:21