Question: In the Boyer-Moore implementation in ALGORITHM 5.7, show that you can set right[c] to the penultimate occurrence of c when c is the last character in the pattern.

Answer:
5.3.13

Consider that we are currently checking the text character in index i (as the leftmost position of the pattern), the pattern character in index j and that a mismatch occurs in the text character at index mi.
Also, consider that the last character in the pattern is c, the index of its last occurrence in the pattern is pMax and its penultimate occurrence is (pMax - x), where x is a number between 1 and pMax. Since c is the last character in the pattern pMax = patternLength - 1.

When the character mismatch happens, the pattern has to be shifted to the right.
If right[c] were equal to pMax then the pattern would be shifted to the right 1 position because pMax will always be higher than j (a mismatch for character c would never occur in the last index of the pattern (pMax), because character c is in that position) and the rule to shift the pattern is: shift positions = max(1, j - pMax).

However, if we had a mismatch in the text character c this means two things:
1- In the inner loop of the algorithm the first character compare is always with the last character in the pattern (c). So there was a comparison of pattern character c with a text character that was a match. The mismatch must have happened in the range [0 … patternLength - 2] of the pattern.
2- Since pMax is equal to patternLength - 1, we know that pMax > j. As mentioned above, this would imply shifting the pattern right 1 position. However, the penultimate occurrence of c is in index (pMax - x). If (pMax - x) >= j, the pattern would still be shifted only 1 position. But if (pMax - x) < j, we can shift the pattern to align mi with the penultimate occurrence of c in the pattern (by incrementing i by j - (pMax - x)). Anything less would align that text character with a pattern character it could not match (such as one to the right of c’s penultimate occurrence).

Therefore, right[c] can be set to the penultimate occurrence of c when c is the last character in the pattern.


Question:
Draw the KMP DFA for the following pattern strings.
a. AAAAAAB
b. AACAAAB
c. ABABABAB
d. ABAABAAABAAAB
e. ABAABCABAABCB

Answer:
5.3.17

a. AAAAAAB

           j   0
pat.charAt(j)  A
           A   1
  dfa[][j] B   0
           …   0

    j   A
    0   —>  1
   / ^
  /   \
  -B,…-

               X
           j   0   1
pat.charAt(j)  A   A
           A   1   2
  dfa[][j] B   0   0
           …   0   0

         A   j    A
    0    —>  1    —>  2
   / ^ <-    |
  /   \ |    |
  -B,…-  -B,…-

                   X
           j   0   1   2
pat.charAt(j)  A   A   A
           A   1   2   3
  dfa[][j] B   0   0   0
           …   0   0   0

         A       A   j   A
    0    —>  1   —>  2   —>  3
   / ^ <-    |       |
  /   \ |    |       |
  -B,…-  -B,…- <--B,…-

                       X
           j   0   1   2   3
pat.charAt(j)  A   A   A   A
           A   1   2   3   4
  dfa[][j] B   0   0   0   0
           …   0   0   0   0

         A       A       A   j   A
    0    —>  1   —>  2   —>  3   —>  4
   / ^ <-    |       |       |
  /   \ |    |       |       |
  -B,…-  -B,…- <--B,…- <--B,…-

                           X
           j   0   1   2   3   4
pat.charAt(j)  A   A   A   A   A
           A   1   2   3   4   5
  dfa[][j] B   0   0   0   0   0
           …   0   0   0   0   0

         A       A       A       A   j   A
    0    —>  1   —>  2   —>  3   —>  4   —>  5
   / ^ <-    |       |       |       |
  /   \ |    |       |       |       |
  -B,…-  -B,…- <--B,…- <--B,…- <--B,…-

                               X
           j   0   1   2   3   4   5
pat.charAt(j)  A   A   A   A   A   A
           A   1   2   3   4   5   6
  dfa[][j] B   0   0   0   0   0   0
           …   0   0   0   0   0   0

         A       A       A       A       A   j    A
    0    —>  1   —>  2   —>  3   —>  4   —>  5    —>  6
   / ^ <-    |       |       |       |       |
  /   \ |    |       |       |       |       |
  -B,…-  -B,…- <--B,…- <--B,…- <--B,…- <--B,…-

                                   X
           j   0   1   2   3   4   5   6
pat.charAt(j)  A   A   A   A   A   A   B
           A   1   2   3   4   5   6   6
  dfa[][j] B   0   0   0   0   0   0   7
           …   0   0   0   0   0   0   0

         A       A       A       A       A        A    j   B
    0    —>  1   —>  2   —>  3   —>  4   —>  5    —>   6   —>  7
   / ^ <-    |       |       |       |       |         |^
  /   \ |    |       |       |       |       |        / \\
  -B,…-  -B,…- <--B,…- <--B,…- <--B,…- <--B,…-  <-C,…-   -A

b. AACAAAB

           j   0
pat.charAt(j)  A
           A   1
  dfa[][j] B   0
           C   0
           …   0

    j    A
    0    —>   1
  /  ^
 /    \
 -B,C,…-

               X
           j   0   1
pat.charAt(j)  A   A
           A   1   2
  dfa[][j] B   0   0
           C   0   0
           …   0   0

         A     j   A
    0    —>    1   —>   2
  /  ^ <-       \
 /    \   \      \
 -B,C,…-   --B,C,…-

                   X
           j   0   1   2
pat.charAt(j)  A   A   C
           A   1   2   2
  dfa[][j] B   0   0   0
           C   0   0   3
           …   0   0   0

         A            A       j    C
    0    —>    1      —>      2    —>   3
  /  ^ <—-      \             |^
 /    \    \     \           / \\
 -B,C,…-    -B,C,…- <-—B,D,…-   -A

               X
           j   0   1   2   3
pat.charAt(j)  A   A   C   A
           A   1   2   2   4
  dfa[][j] B   0   0   0   0
           C   0   0   3   0
           …   0   0   0   0

         A            A            C    j    A
    0    —>    1      —>      2    —>   3    —>   4
  /  ^ <—-      \             |^        |
 /    \    \     \           / \\       |
 -B,C,…-    -B,C,…- <-—B,D,…-   -A      |
       ^                                |
        \                               |
         ————————————————————————-—B,C,…-

                   X
           j   0   1   2   3   4
pat.charAt(j)  A   A   C   A   A
           A   1   2   2   4   5
  dfa[][j] B   0   0   0   0   0
           C   0   0   3   0   0
           …   0   0   0   0   0

         A            A            C         A    j    A
    0    —>    1      —>      2    —>   3    —>   4    —>   5
  /  ^ <—-      \             |^        |         |
 /    \    \     \           / \\       |         |
 -B,C,…-    -B,C,…- <-—B,D,…-   -A      |         |
       ^                                |         |
        \                               |         |
         ————————————————————————-—B,C,…- <-—B,C,…-

                       X
           j   0   1   2   3   4   5
pat.charAt(j)  A   A   C   A   A   A
           A   1   2   2   4   5   6
  dfa[][j] B   0   0   0   0   0   0
           C   0   0   3   0   0   3
           …   0   0   0   0   0   0

                                        ——————————C——————————
         A            A            C    V    A         A   j|    A
    0    —>    1      —>      2    —>   3    —>   4    —>   5    —>   6
  /  ^ <—-      \             |^        |         |         |
 /    \    \     \           / \\       |         |         |
 -B,C,…-    -B,C,…- <-—B,D,…-   -A      |         |         |
       ^                                |         |         |
        \                               |         |         |
         ————————————————————————-—B,C,…- <-—B,C,…- <-—B,D,…-

                       X
           j   0   1   2   3   4   5   6
pat.charAt(j)  A   A   C   A   A   A   B
           A   1   2   2   4   5   6   2
  dfa[][j] B   0   0   0   0   0   0   7
           C   0   0   3   0   0   3   3
           …   0   0   0   0   0   0   0

                              ————————————————————————————————————A————
                              |         ——————————C—————————— <———C———|
         A            A       V    C    V    A         A    |    A   j|    B
    0    —>    1      —>      2    —>   3    —>   4    —>   5    —>   6    —>   7
  /  ^ <—-      \             |^        |         |         |         |
 /    \    \     \           / \\       |         |         |         |
 -B,C,…-    -B,C,…- <-—B,D,…-   -A      |         |         |         |
       ^                                |         |         |         |
        \                               |         |         |         |
         ————————————————————————-—B,C,…- <-—B,C,…- <-—B,D,…- <--—-D,…-

c. ABABABAB

           j   0
pat.charAt(j)  A
           A   1
  dfa[][j] B   0
           …   0

    j   A
    0   —>  1
   / ^
  /   \
  -B,…-

               X
           j   0   1
pat.charAt(j)  A   B
           A   1   1
  dfa[][j] B   0   2
           …   0   0

         A     j    B
    0    —>    1    —>  2
   / ^ <-      |^
  /   \ |     / \\
  -B,…-  -C,…-   -A

               X
           j   0   1   2
pat.charAt(j)  A   B   A
           A   1   1   3
  dfa[][j] B   0   2   0
           …   0   0   0

         A          B   j    A
    0    —>    1    —>  2    —>  3
   / ^ <-      |^       |
  /   \ |     / \\      |
  -B,…-  -C,…-   -A     |
      ^                 |
       \                |
        —————————————B,…-

                   X
           j   0   1   2   3
pat.charAt(j)  A   B   A   B
           A   1   1   3   1
  dfa[][j] B   0   2   0   4
           …   0   0   0   0

               ———————————————A———
               |                 |
         A     V    B        A  j|    B
    0    —>    1    —>  2    —>  3    —>  4
   / ^ <-      |^       |        |
  /   \ |     / \\      |        |
  -B,…-  -C,…-   -A     |        |
      ^                 |        |
       \                |        |
        —————————————B,…- <———C,…-

                       X
           j   0   1   2   3   4
pat.charAt(j)  A   B   A   B   A
           A   1   1   3   1   5
  dfa[][j] B   0   2   0   4   0
           …   0   0   0   0   0

               ———————————————A———
               |                 |
         A     V    B        A   |    B   j    A
    0    —>    1    —>  2    —>  3    —>  4    —>  5
   / ^ <-      |^       |        |        |
  /   \ |     / \\      |        |        |
  -B,…-  -C,…-   -A     |        |        |
      ^                 |        |        |
       \                |        |        |
        —————————————B,…- <———C,…- <———B,…-

                           X
           j   0   1   2   3   4   5
pat.charAt(j)  A   B   A   B   A   B
           A   1   1   3   1   5   1
  dfa[][j] B   0   2   0   4   0   6
           …   0   0   0   0   0   0

               ———————————————A——— <——————————————A—
               |                 |                 |
         A     V    B        A   |    B        A  j|    B
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6
   / ^ <-      |^       |        |        |        |
  /   \ |     / \\      |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |
      ^                 |        |        |        |
       \                |        |        |        |
        —————————————B,…- <———C,…- <———B,…- <———C,…-

                               X
           j   0   1   2   3   4   5   6
pat.charAt(j)  A   B   A   B   A   B   A
           A   1   1   3   1   5   1   7
  dfa[][j] B   0   2   0   4   0   6   0
           …   0   0   0   0   0   0   0

               ———————————————A——— <——————————————A—
               |                 |                 |
         A     V    B        A   |    B        A   |    B   j    A
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7
   / ^ <-      |^       |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |
      ^                 |        |        |        |        |
       \                |        |        |        |        |
        —————————————B,…- <———C,…- <———B,…- <———C,…- <———B,…-

                                   X
           j   0   1   2   3   4   5   6   7
pat.charAt(j)  A   B   A   B   A   B   A   B
           A   1   1   3   1   5   1   7   1
  dfa[][j] B   0   2   0   4   0   6   0   8
           …   0   0   0   0   0   0   0   0

               ———————————————A——— <——————————————A— <——————————————A—
               |                 |                 |                 |
         A     V    B        A   |    B        A   |    B        A  j|    B
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8
   / ^ <-      |^       |        |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |        |
      ^                 |        |        |        |        |        |
       \                |        |        |        |        |        |
        —————————————B,…- <———C,…- <———B,…- <———C,…- <———B,…- <———C,…-

d. ABAABAAABAAAB

           j   0
pat.charAt(j)  A
           A   1
  dfa[][j] B   0
           …   0

    j   A
    0   —>  1
   / ^
  /   \
  -B,…-

               X
           j   0   1
pat.charAt(j)  A   B
           A   1   1
  dfa[][j] B   0   2
           …   0   0

         A     j    B
    0    —>    1    —>  2
   / ^ <-      |^
  /   \ |     / \\
  -B,…-  -C,…-   -A

               X
           j   0   1   2
pat.charAt(j)  A   B   A
           A   1   1   3
  dfa[][j] B   0   2   0
           …   0   0   0

         A          B   j    A
    0    —>    1    —>  2    —>  3
   / ^ <-      |^       |
  /   \ |     / \\      |
  -B,…-  -C,…-   -A     |
      ^                 |
       \                |
        —————————————B,…-

                   X
           j   0   1   2   3
pat.charAt(j)  A   B   A   A
           A   1   1   3   4
  dfa[][j] B   0   2   0   2
           …   0   0   0   0

                        ——————B———
         A          B   V    A  j|    A
    0    —>    1    —>  2    —>  3    —>  4
   / ^ <-      |^       |        |
  /   \ |     / \\      |        |
  -B,…-  -C,…-   -A     |        |
      ^                 |        |
       \                |        |
        —————————————B,…- <———C,…-

                   X
           j   0   1   2   3   4
pat.charAt(j)  A   B   A   A   B
           A   1   1   3   4   1
  dfa[][j] B   0   2   0   2   5
           …   0   0   0   0   0

               ——————————————————————————A—
               |        ——————B———        |
         A     V    B   V    A   |    A  j|    B
    0    —>    1    —>  2    —>  3    —>  4    —>  5
   / ^ <-      |^       |        |        |
  /   \ |     / \\      |        |        |
  -B,…-  -C,…-   -A     |        |        |
      ^                 |        |        |
       \                |        |        |
        —————————————B,…- <———C,…- <———C,…-

                       X
           j   0   1   2   3   4   5
pat.charAt(j)  A   B   A   A   B   A
           A   1   1   3   4   1   6
  dfa[][j] B   0   2   0   2   5   0
           …   0   0   0   0   0   0

               ——————————————————————————A—
               |        ——————B———        |
         A     V    B   V    A   |    A   |    B   j    A
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6
   / ^ <-      |^       |        |        |        |
  /   \ |     / \\      |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |
      ^                 |        |        |        |
       \                |        |        |        |
        —————————————B,…- <———C,…- <———C,…- <———B,…-

                           X
           j   0   1   2   3   4   5   6
pat.charAt(j)  A   B   A   A   B   A   A
           A   1   1   3   4   1   6   7
  dfa[][j] B   0   2   0   2   5   0   2
           …   0   0   0   0   0   0   0

               ——————————————————————————A—
               |        ——————B——— <——————|————————————————B—
         A     V    B   V    A   |    A   |    B        A  j|    A
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7
   / ^ <-      |^       |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |
      ^                 |        |        |        |        |
       \                |        |        |        |        |
        —————————————B,…- <———C,…- <———C,…- <———B,…- <———C,…-

                               X
           j   0   1   2   3   4   5   6   7
pat.charAt(j)  A   B   A   A   B   A   A   A
           A   1   1   3   4   1   6   7   8
  dfa[][j] B   0   2   0   2   5   0   2   5
           …   0   0   0   0   0   0   0   0

               ——————————————————————————A—        —————————————————B—
               |        ——————B——— <——————|————————|———————B—        |
         A     V    B   V    A   |    A   |    B   V    A   |    A  j|    A
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8
   / ^ <-      |^       |        |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |        |
      ^                 |        |        |        |        |        |
       \                |        |        |        |        |        |
        —————————————B,…- <———C,…- <———C,…- <———B,…- <———C,…- <———C,…-

                   X
           j   0   1   2   3   4   5   6   7   8
pat.charAt(j)  A   B   A   A   B   A   A   A   B
           A   1   1   3   4   1   6   7   8   1
  dfa[][j] B   0   2   0   2   5   0   2   5   9
           …   0   0   0   0   0   0   0   0   0

               ——————————————————————————————————————————————————————————————A—
               |                                                              |
               |—————————————————————————A—        —————————————————B—        |
               |        ——————B——— <——————|————————|———————B—        |        |
         A     V    B   V    A   |    A   |    B   V    A   |    A   |    A  j|    B
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9
   / ^ <-      |^       |        |        |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |        |        |
      ^                 |        |        |        |        |        |        |
       \                |        |        |        |        |        |        |
        —————————————B,…- <———C,…- <———C,…- <———B,…- <———C,…- <———C,…- <———C,…-

                       X
           j   0   1   2   3   4   5   6   7   8   9
pat.charAt(j)  A   B   A   A   B   A   A   A   B   A
           A   1   1   3   4   1   6   7   8   1  10
  dfa[][j] B   0   2   0   2   5   0   2   5   9   0
           …   0   0   0   0   0   0   0   0   0   0

               ——————————————————————————————————————————————————————————————A—
               |                                                              |
               |—————————————————————————A—        —————————————————B—        |
               |        ——————B——— <——————|————————|———————B—        |        |
         A     V    B   V    A   |    A   |    B   V    A   |    A   |    A   |    B   j    A
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9    —>  10
   / ^ <-      |^       |        |        |        |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |        |        |        |
      ^                 |        |        |        |        |        |        |        |
       \                |        |        |        |        |        |        |        |
        —————————————B,…- <———C,…- <———C,…- <———B,…- <———C,…- <———C,…- <———C,…- <———B,…-

                           X
           j   0   1   2   3   4   5   6   7   8   9  10
pat.charAt(j)  A   B   A   A   B   A   A   A   B   A   A
           A   1   1   3   4   1   6   7   8   1  10  11
  dfa[][j] B   0   2   0   2   5   0   2   5   9   0   2
           …   0   0   0   0   0   0   0   0   0   0   0

                        ———————————————————————————————————————————————————————————————————————B—
               —————————|————————————————————————————————————————————————————A—                 |
               |        |                                                     |                 |
               |————————|————————————————A—        —————————————————B—        |                 |
               |        |—————B——— <——————|————————|———————B—        |        |                 |
         A     V    B   V    A   |    A   |    B   V    A   |    A   |    A   |    B        A  j|    A
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9    —> 10    —>  11
   / ^ <-      |^       |        |        |        |        |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |        |        |        |        |
      ^                 |        |        |        |        |        |        |        |        |
       \                |        |        |        |        |        |        |        |        |
        —————————————B,…- <———C,…- <———C,…- <———B,…- <———C,…- <———C,…- <———C,…- <———B,…- <———C,…-

                               X
           j   0   1   2   3   4   5   6   7   8   9  10  11
pat.charAt(j)  A   B   A   A   B   A   A   A   B   A   A   A
           A   1   1   3   4   1   6   7   8   1  10  11  12
  dfa[][j] B   0   2   0   2   5   0   2   5   9   0   2   5
           …   0   0   0   0   0   0   0   0   0   0   0   0

                                                   —————————————————————————————————————————————————————B—
                        ———————————————————————————|———————————————————————————————————————————B—        |
               —————————|——————————————————————————|—————————————————————————A—                 |        |
               |        |                          |                          |                 |        |
               |————————|————————————————A—        |————————————————B—        |                 |        |
               |        |—————B——— <——————|————————|———————B—        |        |                 |        |
         A     V    B   V    A   |    A   |    B   V    A   |    A   |    A   |    B        A   |    A  j|    A
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9    —> 10    —> 11    —>  12
   / ^ <-      |^       |        |        |        |        |        |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |        |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |        |        |        |        |        |
      ^                 |        |        |        |        |        |        |        |        |        |
       \                |        |        |        |        |        |        |        |        |        |
        —————————————B,…- <———C,…- <———C,…- <———B,…- <———C,…- <———C,…- <———C,…- <———B,…- <———C,…- <———C,…-

                   X
           j   0   1   2   3   4   5   6   7   8   9  10  11  12
pat.charAt(j)  A   B   A   A   B   A   A   A   B   A   A   A   B
           A   1   1   3   4   1   6   7   8   1  10  11  12   1
  dfa[][j] B   0   2   0   2   5   0   2   5   9   0   2   5  13
           …   0   0   0   0   0   0   0   0   0   0   0   0   0

               ——————————————————————————————————————————————————————————————————————————————————————————————————A—
               |                                   —————————————————————————————————————————————————————B—        |
               |        ———————————————————————————|———————————————————————————————————————————B—        |        |
               |————————|——————————————————————————|—————————————————————————A—                 |        |        |
               |        |                          |                          |                 |        |        |
               |————————|————————————————A—        |————————————————B—        |                 |        |        |
               |        |—————B——— <——————|————————|———————B—        |        |                 |        |        |
         A     V    B   V    A   |    A   |    B   V    A   |    A   |    A   |    B        A   |    A   |    A  j|    B
    0    —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9    —> 10    —> 11    —> 12    —>  13
   / ^ <-      |^       |        |        |        |        |        |        |        |        |        |        |
  /   \ |     / \\      |        |        |        |        |        |        |        |        |        |        |
  -B,…-  -C,…-   -A     |        |        |        |        |        |        |        |        |        |        |
      ^                 |        |        |        |        |        |        |        |        |        |        |
       \                |        |        |        |        |        |        |        |        |        |        |
        —————————————B,…- <———C,…- <———C,…- <———B,…- <———C,…- <———C,…- <———C,…- <———B,…- <———C,…- <———C,…- <———C,…-

e. ABAABCABAABCB

           j   0
pat.charAt(j)  A
           A   1
  dfa[][j] B   0
           C   0
           …   0

     j   A
     0   —>  1
   /   ^
  /     \
  -B,C,…-

               X
           j   0   1
pat.charAt(j)  A   B
           A   1   1
  dfa[][j] B   0   2
           C   0   0
           …   0   0

           A     j    B
     0     —>    1    —>  2
   /   ^ <-      |^
  /     \ |     / \\
  -B,C,…-  -C,…-   -A

               X
           j   0   1   2
pat.charAt(j)  A   B   A
           A   1   1   3
  dfa[][j] B   0   2   0
           C   0   0   0
           …   0   0   0

           A          B   j    A
     0     —>    1    —>  2    —>  3
   /   ^ <-      |^       |
  /     \ |     / \\      |
  -B,C,…-  -C,…-   -A     |
        ^                 |
         \                |
          ———————————B,C,…-

                   X
           j   0   1   2   3
pat.charAt(j)  A   B   A   A
           A   1   1   3   4
  dfa[][j] B   0   2   0   2
           C   0   0   0   0
           …   0   0   0   0

                          ——————B———
           A          B   V    A  j|    A
     0     —>    1    —>  2    —>  3    —>  4
   /   ^ <-      |^       |        |
  /     \ |     / \\      |        |
  -B,C,…-  -C,…-   -A     |        |
        ^                 |        |
         \                |        |
          ———————————B,C,…- <———C,…-

                   X
           j   0   1   2   3   4
pat.charAt(j)  A   B   A   A   B
           A   1   1   3   4   1
  dfa[][j] B   0   2   0   2   5
           C   0   0   0   0   0
           …   0   0   0   0   0

                 ——————————————————————————A—
                 |        ——————B———        |
           A     V    B   V    A   |    A  j|    B
     0     —>    1    —>  2    —>  3    —>  4    —>  5
   /   ^ <-      |^       |        |        |
  /     \ |     / \\      |        |        |
  -B,C,…-  -C,…-   -A     |        |        |
        ^                 |        |        |
         \                |        |        |
          ———————————B,C,…- <———C,…- <———C,…-

                       X
           j   0   1   2   3   4   5
pat.charAt(j)  A   B   A   A   B   C
           A   1   1   3   4   1   3
  dfa[][j] B   0   2   0   2   5   0
           C   0   0   0   0   0   6
           …   0   0   0   0   0   0

                                    ————————————————A—
                 ———————————————————|——————A—        |
                 |        ——————B———|       |        |
           A     V    B   V    A   |V   A   |    B  j|    C
     0     —>    1    —>  2    —>  3    —>  4    —>  5    —>  6
   /   ^ <-      |^       |        |        |        |
  /     \ |     / \\      |        |        |        |
  -B,C,…-  -C,…-   -A     |        |        |        |
        ^                 |        |        |        |
         \                |        |        |        |
          ———————————B,C,…- <———C,…- <———C,…- <—B,D,…-

               X
           j   0   1   2   3   4   5   6
pat.charAt(j)  A   B   A   A   B   C   A
           A   1   1   3   4   1   3   7
  dfa[][j] B   0   2   0   2   5   0   0
           C   0   0   0   0   0   6   0
           …   0   0   0   0   0   0   0

                                    ————————————————A—
                 ———————————————————|——————A—        |
                 |        ——————B———|       |        |
           A     V    B   V    A   |V   A   |    B   |    C   j    A
     0     —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7
   /   ^ <-      |^       |        |        |        |        |
  /     \ |     / \\      |        |        |        |        |
  -B,C,…-  -C,…-   -A     |        |        |        |        |
        ^                 |        |        |        |        |
         \                |        |        |        |        |
          ———————————B,C,…- <———C,…- <———C,…- <—B,D,…- <—B,C,…-

                   X
           j   0   1   2   3   4   5   6   7
pat.charAt(j)  A   B   A   A   B   C   A   B
           A   1   1   3   4   1   3   7   1
  dfa[][j] B   0   2   0   2   5   0   0   8
           C   0   0   0   0   0   6   0   0
           …   0   0   0   0   0   0   0   0

                 —————————————————————————————————————————————————————A—
                 |                  ————————————————A—                 |
                 |——————————————————|——————A—        |                 |
                 |        ——————B———|       |        |                 |
           A     V    B   V    A   |V   A   |    B   |    C        A  j|    B
     0     —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8
   /   ^ <-      |^       |        |        |        |        |        |
  /     \ |     / \\      |        |        |        |        |        |
  -B,C,…-  -C,…-   -A     |        |        |        |        |        |
        ^                 |        |        |        |        |        |
         \                |        |        |        |        |        |
          ———————————B,C,…- <———C,…- <———C,…- <—B,D,…- <—B,C,…- <———C,…-

                       X
           j   0   1   2   3   4   5   6   7   8
pat.charAt(j)  A   B   A   A   B   C   A   B   A
           A   1   1   3   4   1   3   7   1   9
  dfa[][j] B   0   2   0   2   5   0   0   8   0
           C   0   0   0   0   0   6   0   0   0
           …   0   0   0   0   0   0   0   0   0

                 —————————————————————————————————————————————————————A—
                 |                  ————————————————A—                 |
                 |——————————————————|——————A—        |                 |
                 |        ——————B———|       |        |                 |
           A     V    B   V    A   |V   A   |    B   |    C        A   |    B   j    A
     0     —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9
   /   ^ <-      |^       |        |        |        |        |        |        |
  /     \ |     / \\      |        |        |        |        |        |        |
  -B,C,…-  -C,…-   -A     |        |        |        |        |        |        |
        ^                 |        |        |        |        |        |        |
         \                |        |        |        |        |        |        |
          ———————————B,C,…- <———C,…- <———C,…- <—B,D,…- <—B,C,…- <———C,…- <—B,C,…-

                           X
           j   0   1   2   3   4   5   6   7   8   9
pat.charAt(j)  A   B   A   A   B   C   A   B   A   A
           A   1   1   3   4   1   3   7   1   9  10
  dfa[][j] B   0   2   0   2   5   0   0   8   0   2
           C   0   0   0   0   0   6   0   0   0   0
           …   0   0   0   0   0   0   0   0   0   0

                          ——————————————————————————————————————————————————————————————B—
                 —————————|———————————————————————————————————————————A—                 |
                 |        |         ————————————————A—                 |                 |
                 |————————|—————————|——————A—        |                 |                 |
                 |        |—————B———|       |        |                 |                 |
           A     V    B   V    A   |V   A   |    B   |    C        A   |    B        A  j|    A
     0     —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9    —> 10
   /   ^ <-      |^       |        |        |        |        |        |        |        |
  /     \ |     / \\      |        |        |        |        |        |        |        |
  -B,C,…-  -C,…-   -A     |        |        |        |        |        |        |        |
        ^                 |        |        |        |        |        |        |        |
         \                |        |        |        |        |        |        |        |
          ———————————B,C,…- <———C,…- <———C,…- <—B,D,…- <—B,C,…- <———C,…- <—B,C,…- <———C,…-

                               X
           j   0   1   2   3   4   5   6   7   8   9  10
pat.charAt(j)  A   B   A   A   B   C   A   B   A   A   B
           A   1   1   3   4   1   3   7   1   9  10   1
  dfa[][j] B   0   2   0   2   5   0   0   8   0   2  11
           C   0   0   0   0   0   6   0   0   0   0   0
           …   0   0   0   0   0   0   0   0   0   0   0

                 ————————————————————————————————————————————————————————————————————————————————A—
                 |        ——————————————————————————————————————————————————————————————B—        |
                 |————————|———————————————————————————————————————————A—                 |        |
                 |        |         ————————————————A—                 |                 |        |
                 |————————|—————————|——————A—        |                 |                 |        |
                 |        |—————B———|       |        |                 |                 |        |
           A     V    B   V    A   |V   A   |    B   |    C        A   |    B        A   |    A  j|    B
     0     —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9    —> 10    —> 11
   /   ^ <-      |^       |        |        |        |        |        |        |        |        |
  /     \ |     / \\      |        |        |        |        |        |        |        |        |
  -B,C,…-  -C,…-   -A     |        |        |        |        |        |        |        |        |
        ^                 |        |        |        |        |        |        |        |        |
         \                |        |        |        |        |        |        |        |        |
          ———————————B,C,…- <———C,…- <———C,…- <—B,D,…- <—B,C,…- <———C,…- <—B,C,…- <———C,…- <———C,…-

                                   X
           j   0   1   2   3   4   5   6   7   8   9  10  11
pat.charAt(j)  A   B   A   A   B   C   A   B   A   A   B   C
           A   1   1   3   4   1   3   7   1   9  10   1   3
  dfa[][j] B   0   2   0   2   5   0   0   8   0   2  11   0
           C   0   0   0   0   0   6   0   0   0   0   0  12
           …   0   0   0   0   0   0   0   0   0   0   0   0

                                    ——————————————————————————————————————————————————————————————————————A—
                 ———————————————————|————————————————————————————————————————————————————————————A—        |
                 |        ——————————|———————————————————————————————————————————————————B—        |        |
                 |————————|—————————|—————————————————————————————————A—                 |        |        |
                 |        |         |———————————————A—                 |                 |        |        |
                 |————————|—————————|——————A—        |                 |                 |        |        |
                 |        |—————B———|       |        |                 |                 |        |        |
           A     V    B   V    A   |V   A   |    B   |    C        A   |    B        A   |    A   |    B  j|    C
     0     —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9    —> 10    —> 11    —> 12
   /   ^ <-      |^       |        |        |        |        |        |        |        |        |        |
  /     \ |     / \\      |        |        |        |        |        |        |        |        |        |
  -B,C,…-  -C,…-   -A     |        |        |        |        |        |        |        |        |        |
        ^                 |        |        |        |        |        |        |        |        |        |
         \                |        |        |        |        |        |        |        |        |        |
          ———————————B,C,…- <———C,…- <———C,…- <—B,D,…- <—B,C,…- <———C,…- <—B,C,…- <———C,…- <———C,…- <—B,D,…-

                                       X
           j   0   1   2   3   4   5   6   7   8   9  10  11  12
pat.charAt(j)  A   B   A   A   B   C   A   B   A   A   B   C   B
           A   1   1   3   4   1   3   7   1   9  10   1   3   7
  dfa[][j] B   0   2   0   2   5   0   0   8   0   2  11   0  13
           C   0   0   0   0   0   6   0   0   0   0   0  12   0
           …   0   0   0   0   0   0   0   0   0   0   0   0   0

                                                                        ———————————————————————————————————————————A—
                                    ————————————————————————————————————|—————————————————————————————————A—        |
                 ———————————————————|———————————————————————————————————|————————————————————————A—        |        |
                 |        ——————————|———————————————————————————————————|———————————————B—        |        |        |
                 |————————|—————————|—————————————————————————————————A—|                |        |        |        |
                 |        |         |———————————————A—                 ||                |        |        |        |
                 |————————|—————————|——————A—        |                 ||                |        |        |        |
                 |        |—————B———|       |        |                 ||                |        |        |        |
           A     V    B   V    A   |V   A   |    B   |    C        A   |V   B        A   |    A   |    B   |    C  j|    B
     0     —>    1    —>  2    —>  3    —>  4    —>  5    —>  6    —>  7    —>  8    —>  9    —> 10    —> 11    —> 12    —> 13
   /   ^ <-      |^       |        |        |        |        |        |        |        |        |        |        |
  /     \ |     / \\      |        |        |        |        |        |        |        |        |        |        |
  -B,C,…-  -C,…-   -A     |        |        |        |        |        |        |        |        |        |        |
        ^                 |        |        |        |        |        |        |        |        |        |        |
         \                |        |        |        |        |        |        |        |        |        |        |
          ———————————B,C,…- <———C,…- <———C,…- <—B,D,…- <—B,C,…- <———C,…- <—B,C,…- <———C,…- <———C,…- <—B,D,…- <———C,…-


Question: How would you modify the Rabin-Karp algorithm to search for an H-by-V pattern in an N-by-N text?

Answer:
5.3.22

We could compute a pattern hash that is based on each row of V characters in the following way:
We would compute H hashes (one hash for each row), in the same way as RabinKarp algorithm, and would add each value to the patternHash variable.

So the 1-by-4 pattern RENE and the 2-by-2 pattern RE would have different pattern hashes.
                                                  NE

We would then use the same method to compute a hash for every sub matrix H-by-V in the text and would compare this value with the pattern hash. If there is a match in the hashes, we could check each character in the sub matrix (as in the Las Vegas version of Rabin Karp) to check if the pattern was found in the text.

We would use the rolling hash technique in the following way: an initialColumnsHash value would be computed with the hash value of the first H-by-V characters in the text. Every time we moved to a new row in the text (row i), the (i - 1)th row would be subtracted from the initialColumnsHash rolling hash computation and the (i + patternRowLength - 1)th row would be added to the initialColumnsHash rolling hash computation. After this, initialColumnsHash would be compared to patternHash to search for a match.
We then would copy initialColumnsHash’s value to a textHash variable to search horizontally in the text.
Every time we moved to a new column in the text (column j), the (j - patternColumnLength)th column would be subtracted from the textHash rolling hash computation and the jth column would be added to the textHash rolling hash computation. After this, textHash would be compared to patternHash to search for a match.

We would also precompute the powers of alphabetSize^i, for i = 0 … (patternColumnLength - 1) to effectively subtract rows and columns from the rolling hash computations.

Example:

Pattern: RE
         NE
(2-by-2 pattern)

Text: ABCD
      RERE
      DRNE
      XPQZ
(4-by-4 text)

We start by computing the hash of RE in the variable patternHash.
                                  NE

1- We compute the hash of characters AB in initialColumnsHash and compare with patternHash.
                                     RE
They have different values, so we move to the next column.
We also copy the value of initialColumnsHash to textHash.

2- We subtract the value of column A from textHash and add the value of column C, resulting in the hash of BC.
                                   R                                           R                           ER
We compare textHash with patternHash. They have different values, so we move to the next column.

3- We subtract the value of column B from textHash and add the value of column D, resulting in the hash of CD.
                                   E                                           E                           RE
We compare textHash with patternHash. They have different values. There are no more columns to the right, so we move to the next row and to the first column.

4- We subtract the value of row AB from initialColumnsHash and add the value of row DR, resulting in the hash of RE.
                                                                                DR
We compare initialColumnsHash with patternHash. They have different values, so we copy the value of initialColumnsHash to textHash and move to the next column.

5- We subtract the value of column R from textHash and add the value of column R, resulting in the hash of ER.
                                   D                                           N                           RN
We compare textHash with patternHash. They have different values, so we move to the next column.

6- We subtract the value of column E from textHash and add the value of column E, resulting in the hash of RE.
                                   R                                           E                           NE
We compare textHash with patternHash. They have the same values, so we compare each character in the pattern with the current text sub matrix.
There is a match and the pattern was found. We return the result (1,2) which indicates that the pattern was found on row 1 and column 2.

The implementation of this algorithm can be found here:
https://github.com/reneargento/algorithms-sedgewick-wayne/blob/master/src/chapter5/section3/Exercise30_TwoDimensionalSearch.java


Question: Write a program that reads characters one at a time and reports at each instant if the current string is a palindrome. Hint : Use the Rabin-Karp hashing idea.

Answer:
package chapter5.section3;

import edu.princeton.cs.algs4.StdOut;

import java.math.BigInteger;
import java.util.Random;

/**
 * Created by Rene Argento on 01/03/18.
 */
// Based on https://www.geeksforgeeks.org/online-algorithm-for-checking-palindrome-in-a-stream/

// Monte Carlo version - O(N + M) with a probabilistic guarantee of giving the correct output.
// Las Vegas version - Always gives the correct output with a probabilistic guarantee of running in N + M.
public class Exercise23 {

    public class PalindromeStreamChecker {

        // Pattern
        private StringBuilder currentString;

        private long largePrimeNumber; // prime number used to evaluate Rabin-Karp's rolling hash
        private int alphabetSize;

        private long hash;

        // Hash of the left half of the pattern reversed
        private long leftHalfReversedHash;
        // Hash of the right half of the pattern
        private long rightHalfHash;

        PalindromeStreamChecker() {
            currentString = new StringBuilder();

            alphabetSize = 256;
            hash = 1;

            largePrimeNumber = longRandomPrime();
        }

        // A random 31-bit prime
        private long longRandomPrime() {
            BigInteger prime = BigInteger.probablePrime(31, new Random());
            return prime.longValue();
        }

        public boolean checkPalindromeOnline(char character) {

            currentString.append(character);
            int patternLength = currentString.length();

            // Base cases: strings of lengths 1 and 2
            if (patternLength == 1) {
                leftHalfReversedHash = character % largePrimeNumber;

                return true;
            } else if (patternLength == 2) {
                rightHalfHash = character % largePrimeNumber;

                return currentString.charAt(0) == currentString.charAt(1);
            }

            if (patternLength % 2 == 0) {
                // Left string -> add trailing character in left half
                // Right string -> add trailing character in right half
                char characterToBeAddedInLeftString = currentString.charAt((patternLength - 1) / 2);

                hash = (hash * alphabetSize) % largePrimeNumber;

                leftHalfReversedHash = (leftHalfReversedHash + hash * characterToBeAddedInLeftString) % largePrimeNumber;
                rightHalfHash = (rightHalfHash * alphabetSize + character) % largePrimeNumber;
            } else {
                // Left string -> no changes
                // Right string -> remove leading character and add trailing character
                char characterToRemove = currentString.charAt(patternLength / 2);

                rightHalfHash = (alphabetSize * (rightHalfHash + largePrimeNumber
                        - characterToRemove * hash) % largePrimeNumber
                        + character) % largePrimeNumber;
            }

            // Monte Carlo version - If hashes match, a palindrome was found.
//            if (leftHalfReversedHash == rightHalfHash) {
//                return true;
//            }

            // Las Vegas version - If hashes match, compare characters.
            if (leftHalfReversedHash == rightHalfHash) {
                boolean isPalindrome = true;

                for (int index = 0; index < currentString.length() / 2; index++) {
                    if (currentString.charAt(index) != currentString.charAt(currentString.length() - 1 - index)) {
                        isPalindrome = false;
                        break;
                    }
                }

                return isPalindrome;
            }

            return false;
        }
    }

    public static void main(String[] args) {
        Exercise23 exercise23 = new Exercise23();

        StdOut.println("Test 1:");
        PalindromeStreamChecker palindromeStreamChecker1 = exercise23.new PalindromeStreamChecker();
        StdOut.println("Check r: " + palindromeStreamChecker1.checkPalindromeOnline('r') + " Expected: true");
        StdOut.println("Check re: " + palindromeStreamChecker1.checkPalindromeOnline('e') + " Expected: false");
        StdOut.println("Check ree: " + palindromeStreamChecker1.checkPalindromeOnline('e') + " Expected: false");
        StdOut.println("Check reer: " + palindromeStreamChecker1.checkPalindromeOnline('r') + " Expected: true");

        StdOut.println();

        StdOut.println("Test 2:");
        PalindromeStreamChecker palindromeStreamChecker2 = exercise23.new PalindromeStreamChecker();
        StdOut.println("Check a: " + palindromeStreamChecker2.checkPalindromeOnline('a') + " Expected: true");
        StdOut.println("Check ab: " + palindromeStreamChecker2.checkPalindromeOnline('b') + " Expected: false");
        StdOut.println("Check abc: " + palindromeStreamChecker2.checkPalindromeOnline('c') + " Expected: false");
        StdOut.println("Check abcb: " + palindromeStreamChecker2.checkPalindromeOnline('b') + " Expected: false");
        StdOut.println("Check abcba: " + palindromeStreamChecker2.checkPalindromeOnline('a') + " Expected: true");

        StdOut.println();

        StdOut.println("Test 3:");
        PalindromeStreamChecker palindromeStreamChecker3 = exercise23.new PalindromeStreamChecker();
        StdOut.println("Check L: " + palindromeStreamChecker3.checkPalindromeOnline('L') + " Expected: true");
        StdOut.println("Check LE: " + palindromeStreamChecker3.checkPalindromeOnline('E') + " Expected: false");
        StdOut.println("Check LEV: " + palindromeStreamChecker3.checkPalindromeOnline('V') + " Expected: false");
        StdOut.println("Check LEVE: " + palindromeStreamChecker3.checkPalindromeOnline('E') + " Expected: false");
        StdOut.println("Check LEVEL: " + palindromeStreamChecker3.checkPalindromeOnline('L') + " Expected: true");
        StdOut.println("Check LEVEL0: " + palindromeStreamChecker3.checkPalindromeOnline('0') + " Expected: false");
    }

}


Question: Find all occurrences. Add a method findAll() to each of the four substring search algorithms given in the text that returns an Iterable<Integer> that allows clients to iterate through all offsets of the pattern in the text.

Answer:
package chapter5.section3;

import chapter1.section3.Queue;
import edu.princeton.cs.algs4.StdOut;

import java.util.StringJoiner;

/**
 * Created by Rene Argento on 02/03/18.
 */
public class Exercise24_FindAllOccurrences {

    public class BruteForceSubstringSearchFindAll extends BruteForceSubstringSearch {

        BruteForceSubstringSearchFindAll(String pattern) {
            super(pattern);
        }

        // Finds all the occurrences of pattern in the text
        public Iterable<Integer> findAll(String text) {
            Queue<Integer> offsets = new Queue<>();

            int occurrenceIndex = searchFromIndex(text, 0);

            while (occurrenceIndex != text.length()) {
                offsets.enqueue(occurrenceIndex);
                occurrenceIndex = searchFromIndex(text, occurrenceIndex + 1);
            }

            return offsets;
        }
    }

    public class KnuthMorrisPrattFindAll extends KnuthMorrisPratt {

        KnuthMorrisPrattFindAll(String pattern) {
            super(pattern);
        }

        // Finds all the occurrences of pattern in the text
        public Iterable<Integer> findAll(String text) {
            Queue<Integer> offsets = new Queue<>();

            int occurrenceIndex = searchFromIndex(text, 0);

            while (occurrenceIndex != text.length()) {
                offsets.enqueue(occurrenceIndex);
                occurrenceIndex = searchFromIndex(text, occurrenceIndex + 1);
            }

            return offsets;
        }
    }

    public class BoyerMooreFindAll extends BoyerMoore {

        BoyerMooreFindAll(String pattern) {
            super(pattern);
        }

        // Finds all the occurrences of pattern in the text
        public Iterable<Integer> findAll(String text) {
            Queue<Integer> offsets = new Queue<>();

            int occurrenceIndex = searchFromIndex(text, 0);

            while (occurrenceIndex != text.length()) {
                offsets.enqueue(occurrenceIndex);
                occurrenceIndex = searchFromIndex(text, occurrenceIndex + 1);
            }

            return offsets;
        }
    }

    public class RabinKarpFindAll extends RabinKarp {

        RabinKarpFindAll(String pattern, boolean isMonteCarloVersion) {
            super(pattern, isMonteCarloVersion);
        }

        // Finds all the occurrences of pattern in the text
        public Iterable<Integer> findAll(String text) {
            Queue<Integer> offsets = new Queue<>();

            int occurrenceIndex = searchFromIndex(text, 0);

            while (occurrenceIndex != text.length()) {
                offsets.enqueue(occurrenceIndex);

                if (occurrenceIndex + 1 >= text.length()) {
                    break;
                }

                occurrenceIndex = searchFromIndex(text, occurrenceIndex + 1);
            }

            return offsets;
        }
    }

    public static void main(String[] args) {
        Exercise24_FindAllOccurrences findAllOccurrences = new Exercise24_FindAllOccurrences();

        StdOut.println("*** Bruteforce implementation tests ***");
        findAllOccurrences.test(SubstringSearch.BRUTEFORCE);

        StdOut.println("*** Knuth-Morris-Pratt tests ***");
        findAllOccurrences.test(SubstringSearch.KNUTH_MORRIS_PRATT);

        StdOut.println("*** Boyer-Moore tests ***");
        findAllOccurrences.test(SubstringSearch.BOYER_MOORE);

        StdOut.println("*** Rabin-Karp tests ***");
        findAllOccurrences.test(SubstringSearch.RABIN_KARP);
    }

    private void test(int substringSearchMethodId) {

        String text = "abcdrenetestreneabdreneabcdd";

        String pattern1 = "rene";
        SubstringSearch substringSearch1 = createSubstringSearch(substringSearchMethodId, pattern1);

        if (substringSearch1 == null) {
            return;
        }

        StringJoiner offsets1 = new StringJoiner(", ");
        for (int offset : substringSearch1.findAll(text)) {
            offsets1.add(String.valueOf(offset));
        }

        StdOut.println("Offsets 1: " + offsets1.toString());
        StdOut.println("Expected: 4, 12, 19\n");

        String pattern2 = "abcd";
        SubstringSearch substringSearch2 = createSubstringSearch(substringSearchMethodId, pattern2);

        StringJoiner offsets2 = new StringJoiner(", ");
        for (int offset : substringSearch2.findAll(text)) {
            offsets2.add(String.valueOf(offset));
        }

        StdOut.println("Offsets 2: " + offsets2.toString());
        StdOut.println("Expected: 0, 23\n");

        String pattern3 = "d";
        SubstringSearch substringSearch3 = createSubstringSearch(substringSearchMethodId, pattern3);

        StringJoiner offsets3 = new StringJoiner(", ");
        for (int offset : substringSearch3.findAll(text)) {
            offsets3.add(String.valueOf(offset));
        }

        StdOut.println("Offsets 3: " + offsets3.toString());
        StdOut.println("Expected: 3, 18, 26, 27\n");

        String pattern4 = "zzz";
        SubstringSearch substringSearch4 = createSubstringSearch(substringSearchMethodId, pattern4);

        StringJoiner offsets4 = new StringJoiner(", ");
        for (int offset : substringSearch4.findAll(text)) {
            offsets4.add(String.valueOf(offset));
        }

        StdOut.println("Offsets 4: " + offsets4.toString());
        StdOut.println("Expected: \n");
    }

    private SubstringSearch createSubstringSearch(int substringSearchMethodId, String pattern) {
        SubstringSearch substringSearch = null;

        switch (substringSearchMethodId) {
            case SubstringSearch.BRUTEFORCE:
                substringSearch = new BruteForceSubstringSearchFindAll(pattern);
                break;
            case SubstringSearch.KNUTH_MORRIS_PRATT:
                substringSearch = new KnuthMorrisPrattFindAll(pattern);
                break;
            case SubstringSearch.BOYER_MOORE:
                substringSearch = new BoyerMooreFindAll(pattern);
                break;
            case SubstringSearch.RABIN_KARP:
                substringSearch = new RabinKarpFindAll(pattern, true);
                break;
        }

        return substringSearch;
    }

}


Question: Tandem repeat search. A tandem repeat of a base string b in a string s is a substring of s having at least two consecutive copies b (nonoverlapping). Develop and implement a linear-time algorithm that, given two strings b and s, returns the index of the beginning of the longest tandem repeat of b in s. For example, your program should return 3 when b is abcab and s is abcabcababcababcababcab.

Answer:
package chapter5.section3;

import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 03/03/18.
 */
public class Exercise27_TandemRepeatSearch {

    // Based on https://algs4.cs.princeton.edu/53substring/
    // O(N + M)
    public class KnuthMorrisPrattTandemRepeat {

        private String pattern;
        private int[][] dfa;  // deterministic-finite-automaton
        private int baseStringLength;
        private int tandemRepeat;

        public KnuthMorrisPrattTandemRepeat(String baseString, String text) {
            if (baseString == null || baseString.length() == 0) {
                throw new IllegalArgumentException("Invalid base string");
            }
            if (text == null) {
                throw new IllegalArgumentException("Invalid text");
            }

            // Create the Knuth-Morris-Pratt DFA for k concatenated copies of baseString,
            // where k = textLength / baseStringLength
            StringBuilder pattern = new StringBuilder();

            int maxNumberOfRepeats = text.length() / baseString.length();

            for (int repeat = 0; repeat < maxNumberOfRepeats; repeat++) {
                pattern.append(baseString);
            }

            this.pattern = pattern.toString();
            int patternLength = pattern.length();
            int alphabetSize = 256;
            baseStringLength = baseString.length();
            tandemRepeat = -1;

            dfa = new int[alphabetSize][patternLength];
            dfa[pattern.charAt(0)][0] = 1;

            int restartState = 0;

            for (int patternIndex = 1; patternIndex < patternLength; patternIndex++) {
                // Compute dfa[][patternIndex]
                for (int currentChar = 0; currentChar < alphabetSize; currentChar++) {
                    dfa[currentChar][patternIndex] = dfa[currentChar][restartState]; // Copy mismatch cases
                }
                dfa[pattern.charAt(patternIndex)][patternIndex] = patternIndex + 1;  // Set match case
                restartState = dfa[pattern.charAt(patternIndex)][restartState];      // Update restart state
            }

            computeTandemRepeat(text);
        }

        private void computeTandemRepeat(String text) {
            int textIndex;
            int patternIndex;

            // A tandem repeat is composed of at least 2 consecutive occurrences of the base string.
            // If 1 occurrence were enough, we would initialize maxPatternIndexMatched with 0.
            int maxPatternIndexMatched = baseStringLength;

            for (textIndex = 0, patternIndex = 0; textIndex < text.length() && patternIndex < pattern.length(); textIndex++) {
                patternIndex = dfa[text.charAt(textIndex)][patternIndex];

                if (patternIndex % baseStringLength == 0 && patternIndex > maxPatternIndexMatched) {
                    tandemRepeat = textIndex - patternIndex + 1;
                    maxPatternIndexMatched = patternIndex;
                }
            }
        }

        public int findTandemRepeat() {
            return tandemRepeat;
        }
    }

    public static void main(String[] args) {
        Exercise27_TandemRepeatSearch tandemRepeatSearch = new Exercise27_TandemRepeatSearch();

        String baseString1 = "abcab";
        String text1 = "abcabcababcababcababcab";

        KnuthMorrisPrattTandemRepeat knuthMorrisPrattTandemRepeat1 =
                tandemRepeatSearch.new KnuthMorrisPrattTandemRepeat(baseString1, text1);
        int tandemRepeat1 = knuthMorrisPrattTandemRepeat1.findTandemRepeat();
        StdOut.println("Tandem repeat 1: " + tandemRepeat1 + " Expected: 3");

        String baseString2 = "rene";
        String text2 = "renereneabrenerenereneab";

        KnuthMorrisPrattTandemRepeat knuthMorrisPrattTandemRepeat2 =
                tandemRepeatSearch.new KnuthMorrisPrattTandemRepeat(baseString2, text2);
        int tandemRepeat2 = knuthMorrisPrattTandemRepeat2.findTandemRepeat();
        StdOut.println("Tandem repeat 2: " + tandemRepeat2 + " Expected: 10");

        String baseString3 = "abcab";
        String text3 = "abcababcababcababcabreabcab";

        KnuthMorrisPrattTandemRepeat knuthMorrisPrattTandemRepeat3 =
                tandemRepeatSearch.new KnuthMorrisPrattTandemRepeat(baseString3, text3);
        int tandemRepeat3 = knuthMorrisPrattTandemRepeat3.findTandemRepeat();
        StdOut.println("Tandem repeat 3: " + tandemRepeat3 + " Expected: 0");

        String baseString4 = "rene";
        String text4 = "abcabcabrenereneababcab";

        KnuthMorrisPrattTandemRepeat knuthMorrisPrattTandemRepeat4 =
                tandemRepeatSearch.new KnuthMorrisPrattTandemRepeat(baseString4, text4);
        int tandemRepeat4 = knuthMorrisPrattTandemRepeat4.findTandemRepeat();
        StdOut.println("Tandem repeat 4: " + tandemRepeat4 + " Expected: 8");

        String baseString5 = "rene";
        String text5 = "abcabcababcababcababcab";

        KnuthMorrisPrattTandemRepeat knuthMorrisPrattTandemRepeat5 =
                tandemRepeatSearch.new KnuthMorrisPrattTandemRepeat(baseString5, text5);
        int tandemRepeat5 = knuthMorrisPrattTandemRepeat5.findTandemRepeat();
        StdOut.println("Tandem repeat 5: " + tandemRepeat5 + " Expected: -1");

        // A tandem repeat requires at least 2 consecutive occurrences of baseString in the text,
        // so the two following tests should return -1.

        String baseString6 = "a";
        String text6 = "abcde";

        KnuthMorrisPrattTandemRepeat knuthMorrisPrattTandemRepeat6 =
                tandemRepeatSearch.new KnuthMorrisPrattTandemRepeat(baseString6, text6);
        int tandemRepeat6 = knuthMorrisPrattTandemRepeat6.findTandemRepeat();
        StdOut.println("Tandem repeat 6: " + tandemRepeat6 + " Expected: -1");

        String baseString7 = "a";
        String text7 = "abada";

        KnuthMorrisPrattTandemRepeat knuthMorrisPrattTandemRepeat7 =
                tandemRepeatSearch.new KnuthMorrisPrattTandemRepeat(baseString7, text7);
        int tandemRepeat7 = knuthMorrisPrattTandemRepeat7.findTandemRepeat();
        StdOut.println("Tandem repeat 7: " + tandemRepeat7 + " Expected: -1");
    }

}


Question: Random patterns. How many character compares are needed to do a substring search for a random pattern of length 100 in a given text?

Answer:
5.3.31 - Random patterns

None. The method
public boolean search(char[] text) {
    return false;
}
is quite effective for this problem, since the chances of a random pattern of length 100 appearing in any text are so low that you may consider it to be 0.


Question:
Timings. Write a program that times the four methods for the task of searchng for the substring
it is a far far better thing that i do than i have ever done
in the text of Tale of Two Cities (tale.txt). Discuss the extent to which your results validate the hypthotheses about performance that are stated in the text.

Answer:
// Exercise39_Timings.java
package chapter5.section3;

import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.Stopwatch;
import util.Constants;
import util.FileUtil;

/**
 * Created by Rene Argento on 09/03/18.
 */
// The original text in the Tale of Two Cities file is:
// "It is a far, far better thing that I do, than I have ever done"
public class Exercise39_Timings {

    private void doExperiment() {
        String taleOfTwoCitiesFile = Constants.FILES_PATH + Constants.TALE_OF_TWO_CITIES_FILE;
        String taleOfTwoCitiesText = FileUtil.getAllCharactersFromFile(taleOfTwoCitiesFile, true, true);
        String pattern = "it is a far far better thing that I do than I have ever done";

        String[] substringSearchMethods = {
                SubstringSearch.BRUTEFORCE_METHOD,
                SubstringSearch.KNUTH_MORRIS_PRATT_METHOD,
                SubstringSearch.BOYER_MOORE_METHOD,
                SubstringSearch.RABIN_KARP_METHOD
        };

        StdOut.printf("%20s %10s\n", "Method |", "Time spent");

        for (int substringSearchMethod = 0; substringSearchMethod < substringSearchMethods.length; substringSearchMethod++) {
            SubstringSearch substringSearch;

            switch (substringSearchMethod) {
                case SubstringSearch.BRUTEFORCE:
                    substringSearch = new BruteForceSubstringSearch(pattern);
                    break;
                case SubstringSearch.KNUTH_MORRIS_PRATT:
                    substringSearch = new KnuthMorrisPratt(pattern);
                    break;
                case SubstringSearch.BOYER_MOORE:
                    substringSearch = new BoyerMoore(pattern);
                    break;
                default:
                    substringSearch = new RabinKarp(pattern, true);
                    break;
            }

            Stopwatch stopwatch = new Stopwatch();
            substringSearch.search(taleOfTwoCitiesText);
            double timeSpent = stopwatch.elapsedTime();

            printResults(substringSearchMethods[substringSearchMethod], timeSpent);
        }
    }

    private void printResults(String substringSearchMethod, double timeSpent) {
        StdOut.printf("%18s %12.2f\n", substringSearchMethod, timeSpent);
    }

    public static void main(String[] args) {
        new Exercise39_Timings().doExperiment();
    }

}

Additional notes/results:
5.3.39 - Timings

            Method | Time spent
        Bruteforce         0.01
Knuth-Morris-Pratt         0.01
       Boyer-Moore         0.00
        Rabin-Karp         0.04

The results validate the hypotheses about performance stated in the text:
Both brute force and Knuth-Morris-Pratt methods took 0.01 seconds to do the search, which is aligned with their expected performance of 1.1N operations when searching in typical texts.
Boyer-Moore took 0.00 seconds to do the search, which suggests that it did a sublinear number of operations. This is aligned with its expected performance of N / M operations when searching in typical texts.
Rabin-Karp took 0.04 seconds to do the search, a longer time than all other three methods. However, this is expected according to the hypothesis in the text that it performs 7N operations when searching in typical texts.


Question:
Give a brief English description of each of the following REs:
a. .*
b. A.*A | A
c. .*ABBABBA.*
d. .* A.*A.*A.*A.*

Answer:
5.4.2

a. Any string (including the empty string).
b. Strings that start and end with an A.
c. Strings that contain the palindrome ABBABBA.
d. Strings that contain at least 4 A's, not necessarily consecutive.


Question: What is the maximum number of different strings that can be described by a regular expression with M or operators and no closure operators (parentheses and concatenation are allowed)?

Answer:
5.4.3

The maximum number of different strings that can be described by a regular expression with M or operators and no closure operators is 2^M, which happens when every position yields two choices.

Example pattern with M = 4:
(A|B)(A|B)(A|B)(A|B)

On that pattern every position has two choices, which will yield 2^4 = 16 strings:
AAAA
BAAA, ABAA, AABA, AAAB
BBAA, BABA, BAAB, ABBA, ABAB, AABB
BBBA, BBAB, BABB, ABBB
BBBB

Thanks to luowyang (https://github.com/luowyang) for the correct solution to this exercise:
https://github.com/reneargento/algorithms-sedgewick-wayne/issues/97


Question: Draw the NFA corresponding to the pattern ( ( ( A | B ) * | C D * | E F G ) * ) * .

Answer:
5.4.4

Pattern: (((A|B)*|CD*|EFG)*)*

NFA:
 ————————————————————————————————————————————————————————————————————————————————————————————————
 |    —————————————————————————————————————————————————————————————————————————————————         |
 |    |                                  —————————————————————————————————————————    |         |
 |    |    ——————————————————————————    |         ——————    |                   |    |         |
 |    |    |                        |    |         |    |    |                   |    |         |
0V   1V   2V    3    4    5    6   7|   8|    9  10V  11|  12|   13   14   15  16V  17|   18  19|   20
 ( -> ( -> ( -> A -> |    B -> ) -> * -> |    C -> D -> * -> |    E -> F -> G -> ) -> * -> ) -> * ->
 |    |    |         |    ^    ^    ^         ^    |    ^         ^                   ^         ^
 |    |    |         |____|____|    |         |    |    |         |                   |         |
 |    |    |______________|         |         |     —————         |                   |         |
 |    |    |________________________|         |                   |                   |         |
 |    |                                       |                   |                   |         |
 |    —————————————————————————————————————————————————————————————————————————————————         |
 |                                                                                |
  ———————————————————————————————————————————————————————————————————————————————————————————————


Question: Draw the digraph of ε-transitions for the NFA from Exercise 5.4.4.

Answer:
5.4.5

Digraph of e-transitions:

———————————————————————————————————————————————————————————————————————————————————————————————————————————
|    ——————————————————————————————————————————————————————————————————————————————————————————           |
|    |    ———————————————————————————    ————————————————————————————————————————————————     |           |
|    |    |         ____________    |    |          _______     |                       |     |           |
|    |    |         |          |    |    |          |     |     |                       |     |           |
V    V    V         |          V    |    |          |     V     |                       V     |           |
0 -> 1 -> 2 -> 3    4     5    6 -> 7 -> 8    9    10    11 -> 12    13    14    15    16 -> 17 -> 18 -> 19 -> 20
|    |    |               ^         ^         ^     ^     |           ^                       ^           ^
|    |    |_______________|         |         |     |     |           |                       |           |
|    |    |_________________________|         |     ———————           |                       |           |
|    |                                        |                       |                       |           |
|    ——————————————————————————————————————————————————————————————————————————————————————————           |
———————————————————————————————————————————————————————————————————————————————————————————————————————————


Question: Give the sets of states reachable by your NFA from EXERCISE 5.4.4 after each character match and susbsequent ε-transitions for the input A B B A C E F G E F G C A A B .

Answer:
5.4.6

Input: A B B A C E F G E F G C A A B

0 1 2 3 5 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions from start

4 : set of states reachable after matching A

0 1 2 3 4 5 6 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A

6 : set of states reachable after matching A B

0 1 2 3 5 6 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B

6 : set of states reachable after matching A B B

0 1 2 3 5 6 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B

4 : set of states reachable after matching A B B A

0 1 2 3 4 5 6 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B A

10 : set of states reachable after matching A B B A C

0 1 2 3 5 7 8 9 10 11 12 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B A C

14 : set of states reachable after matching A B B A C E

14 : set of states reachable via e-transitions after matching A B B A C E

15 : set of states reachable after matching A B B A C E F

15 : set of states reachable via e-transitions after matching A B B A C E F

16 : set of states reachable after matching A B B A C E F G

0 1 2 3 5 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B A C E F G

14 : set of states reachable after matching A B B A C E F G E

14 : set of states reachable via e-transitions after matching A B B A C E F G E

15 : set of states reachable after matching A B B A C E F G E F

15 : set of states reachable via e-transitions after matching A B B A C E F G E F

16 : set of states reachable after matching A B B A C E F G E F G

0 1 2 3 5 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B A C E F G E F G

10 : set of states reachable after matching A B B A C E F G E F G C

0 1 2 3 5 7 8 9 10 11 12 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B A C E F G E F G C

4 : set of states reachable after matching A B B A C E F G E F G C A

0 1 2 3 4 5 6 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B A C E F G E F G C A

4 : set of states reachable after matching A B B A C E F G E F G C A A

0 1 2 3 4 5 6 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B A C E F G E F G C A A

6 : set of states reachable after matching A B B A C E F G E F G C A A B

0 1 2 3 5 6 7 8 9 13 16 17 18 19 20 : set of states reachable via e-transitions after matching A B B A C E F G E F G C A A B


Question:
Write a regular expression for each of the following sets of binary strings:
a. Contains at least three consecutive 1s
b. Contains the substring 110
c. Contains the substring 1101100
d. Does not contain the substring 110

Answer:
5.4.8

a. Contains at least three consecutive 1s: (0|1)*(111)+(0|1)*
b. Contains the substring 110: (0|1)*110(0|1)*
c. Contains the substring 1101100: (0|1)*1101100(0|1)*
d. Does not contain the substring 110: (0|10)*1*


Question:
Write a regular expression for each of the following sets of binary strings:
a. Has at least 3 characters, and the third character is 0
b. Number of 0s is a multiple of 3
c. Starts and ends with the same character
d. Odd length
e. Starts with 0 and has odd length, or starts with 1 and has even length
f. Length is at least 1 and at most 3

Answer:
a. At least 3 characters, third character is 0:
`(0|1)(0|1)0(0|1)*`

b. Number of 0s is a multiple of 3:
`1*(01*01*01*)*`

c. Starts and ends with the same character:
`0|1|0(0|1)*0|1(0|1)*1`

d. Odd length:
`((0|1)(0|1))*(0|1)`

e. Starts with 0 and has odd length, or starts with 1 and has even length:
`0((0|1)(0|1))*|1(0|1)((0|1)(0|1))*`

f. Length is at least 1 and at most 3:
`(0|1)|(0|1)(0|1)|(0|1)(0|1)(0|1)`


Question:
Challenging REs. Construct an RE that describes each of the following sets of strings over the binary alphabet:
a. All strings except 11 or 111
b. Strings with 1 in every odd-number bit position
c. Strings with at least two 0s and at most one 1
d. Strings with no two consecutive 1s

Answer:
5.4.13 - Challenging REs

a. All strings except 11 or 111: 1|(1*01*|1111(0|1)*)*
b. Strings with 1 in every odd-number bit position: (10|11)*1*
c. Strings with at least two 0s and at most one 1: 1?00+|0+1?0+|00+1?
d. Strings with no two consecutive 1s: (0|10)*1?


Question: Wildcard. Add to NFA the capability to handle wildcards.

Answer:
package chapter5.section4;

import chapter1.section3.Bag;
import chapter4.section2.DirectedDFS;
import edu.princeton.cs.algs4.StdOut;

/**
 * Created by Rene Argento on 23/03/18.
 */
public class Exercise17_Wildcard {

    public class RegularExpressionMatcherWildcard extends RegularExpressionMatcher {

        public RegularExpressionMatcherWildcard(String regularExpressionString) {
            super(regularExpressionString);
        }

        @Override
        public boolean recognizes(String text) {
            Bag<Integer> allPossibleStates = new Bag<>();
            DirectedDFS directedDFS = new DirectedDFS(digraph, 0);

            for (int vertex = 0; vertex < digraph.vertices(); vertex++) {
                if (directedDFS.marked(vertex)) {
                    allPossibleStates.add(vertex);
                }
            }

            for (int i = 0; i < text.length(); i++) {
                // Compute possible NFA states for text[i + 1]
                Bag<Integer> states = new Bag<>();

                for (int vertex : allPossibleStates) {
                    if (vertex < numberOfStates) {
                        if (regularExpression[vertex] == text.charAt(i) || regularExpression[vertex] == '.') {
                            states.add(vertex + 1);
                        }
                    }
                }

                allPossibleStates = new Bag<>();
                directedDFS = new DirectedDFS(digraph, states);

                for (int vertex = 0; vertex < digraph.vertices(); vertex++) {
                    if (directedDFS.marked(vertex)) {
                        allPossibleStates.add(vertex);
                    }
                }

                // Optimization if no states are reachable
                if (allPossibleStates.size() == 0) {
                    return false;
                }
            }

            for (int vertex : allPossibleStates) {
                if (vertex == numberOfStates) {
                    return true;
                }
            }

            return false;
        }

    }

    public static void main(String[] args) {
        Exercise17_Wildcard wildcard = new Exercise17_Wildcard();

        String pattern1 = ".*NEEDLE.*";
        RegularExpressionMatcherWildcard regularExpressionMatcherWildcard1 =
                wildcard.new RegularExpressionMatcherWildcard(pattern1);
        String text1 = "A HAYSTACK NEEDLE IN";
        boolean matches1 = regularExpressionMatcherWildcard1.recognizes(text1);
        StdOut.println("Text 1 check: " + matches1 + " Expected: true");

        String pattern2 = "R.N.1.3";
        RegularExpressionMatcherWildcard regularExpressionMatcherWildcard2 =
                wildcard.new RegularExpressionMatcherWildcard(pattern2);
        String text2 = "RENE123";
        boolean matches2 = regularExpressionMatcherWildcard2.recognizes(text2);
        StdOut.println("Text 2 check: " + matches2 + " Expected: true");

        String text3 = "RRNN193";
        boolean matches3 = regularExpressionMatcherWildcard2.recognizes(text3);
        StdOut.println("Text 3 check: " + matches3 + " Expected: true");

        String text4 = "RENE333";
        boolean matches4 = regularExpressionMatcherWildcard2.recognizes(text4);
        StdOut.println("Text 4 check: " + matches4 + " Expected: false");
    }

}


Question: Proof. Develop a version of NFA that prints a proof that a given string is in the language recognized by the NFA (a sequence of state transitions that ends in the accept state).

Answer:
package chapter5.section4;

import chapter1.section3.Bag;
import chapter1.section3.Stack;
import chapter4.section2.Digraph;
import edu.princeton.cs.algs4.StdOut;

import java.util.StringJoiner;

/**
 * Created by Rene Argento on 25/03/18.
 */
@SuppressWarnings("unchecked")
public class Exercise22_Proof {

    private class State {
        private int id;
        private State previous;

        State(int id, State previous) {
            this.id = id;
            this.previous = previous;
        }
    }

    public class RegularExpressionMatcherWithProof extends RegularExpressionMatcher {

        public RegularExpressionMatcherWithProof(String regularExpression) {
            super(regularExpression);
        }

        @Override
        public boolean recognizes(String text) {
            Bag<State> allPossibleStates = new Bag<>();
            State sourceState = new State(0, null);
            DirectedDFS directedDFS = new DirectedDFS(digraph, sourceState);

            for (State newSate : directedDFS.getNewStates()) {
                allPossibleStates.add(newSate);
            }

            for (int i = 0; i < text.length(); i++) {
                // Compute possible NFA states for text[i + 1]
                Bag<State> states = new Bag<>();

                for (State state : allPossibleStates) {
                    if (state.id < numberOfStates) {

                        if (setsMatchMap.contains(state.id)) {
                            recognizeSet(text, i, state, states);
                        } else if (regularExpression[state.id] == text.charAt(i)
                                || regularExpression[state.id] == '.') {
                            addNextState(states, state, state.id + 1);
                        }
                    }
                }

                allPossibleStates = new Bag<>();
                directedDFS = new DirectedDFS(digraph, states);

                if (directedDFS.getNewStates() != null) {
                    for (State newSate : directedDFS.getNewStates()) {
                        allPossibleStates.add(newSate);
                    }
                } else {
                    // Optimization if no states are reachable
                    StdOut.println("Text was not recognized by the DFA");
                    return false;
                }
            }

            for (State state : allPossibleStates) {
                if (state.id == numberOfStates) {
                    printProof(state);
                    return true;
                }
            }

            StdOut.println("Text was not recognized by the DFA");
            return false;
        }

        private void recognizeSet(String text, int index, State state, Bag<State> states) {
            int indexOfRightSquareBracket = setsMatchMap.get(state.id);

            // Is it a range?
            if (regularExpression[state.id + 1] == '-') { // No need to worry about out of bounds indexes
                char leftRangeIndex = regularExpression[state.id];
                char rightRangeIndex = regularExpression[state.id + 2];

                if (leftRangeIndex <= text.charAt(index) && text.charAt(index) <= rightRangeIndex) {
                    if (!isCharPartOfComplementSet(text, index, state.id)) {
                        addNextState(states, state, indexOfRightSquareBracket);
                    }
                } else if (setsComplementMap.contains(state.id)
                        && !isCharPartOfComplementSet(text, index, state.id)) {
                    addNextState(states, state, indexOfRightSquareBracket);
                }
            } else if (regularExpression[state.id] == text.charAt(index) || regularExpression[state.id] == '.') {
                if (!isCharPartOfComplementSet(text, index, state.id)) {
                    addNextState(states, state, indexOfRightSquareBracket);
                }
            } else if (setsComplementMap.contains(state.id) && !isCharPartOfComplementSet(text, index, state.id)) {
                addNextState(states, state, indexOfRightSquareBracket);
            }
        }

        private void addNextState(Bag<State> states, State currentState, int nextStateId) {
            states.add(new State(nextStateId, currentState));
        }

        private void printProof(State state) {
            Stack<State> states = new Stack<>();

            states.push(state);
            while (state.previous != null) {
                states.push(state.previous);
                state = state.previous;
            }

            StringJoiner proof = new StringJoiner(" -> ");
            while (!states.isEmpty()) {
                proof.add(String.valueOf(states.pop().id));
            }

            StdOut.println(proof);
        }
    }

    public class DirectedDFS {

        private boolean[] visited;
        private Bag<State> newStates;

        public DirectedDFS(Digraph digraph, State source) {
            visited = new boolean[digraph.vertices()];
            newStates = new Bag<>();

            dfs(digraph, source);
        }

        public DirectedDFS(Digraph digraph, Iterable<State> sources) {
            visited = new boolean[digraph.vertices()];
            newStates = new Bag<>();

            for (State source : sources) {
                if (!visited[source.id]) {
                    dfs(digraph, source);
                }
            }
        }

        private void dfs(Digraph digraph, State source) {
            visited[source.id] = true;
            newStates.add(source);

            for (int neighbor : digraph.adjacent(source.id)) {
                if (!visited[neighbor]) {
                    State newState = new State(neighbor, source);
                    newStates.add(newState);

                    dfs(digraph, newState);
                }
            }
        }

        public boolean marked(int vertex) {
            return visited[vertex];
        }

        public Bag<State> getNewStates() {
            return newStates;
        }
    }

    public static void main(String[] args) {
        Exercise22_Proof proof = new Exercise22_Proof();

        String pattern1 = "RENE[^ABC]";
        Exercise22_Proof.RegularExpressionMatcherWithProof regularExpressionMatcherWithProof1 =
                proof.new RegularExpressionMatcherWithProof(pattern1);
        String text1 = "RENED";
        StdOut.print("Proof 1: ");
        regularExpressionMatcherWithProof1.recognizes(text1);
        StdOut.println("Expected: 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 9 -> 10");

        String pattern2 = "A[^A-Z0]+Z";
        Exercise22_Proof.RegularExpressionMatcherWithProof regularExpressionMatcherWithProof2 =
                proof.new RegularExpressionMatcherWithProof(pattern2);
        String text2 = "AbZ";
        StdOut.print("\nProof 2: ");
        regularExpressionMatcherWithProof2.recognizes(text2);
        StdOut.println("Expected: 0 -> 1 -> 2 -> 3 -> 7 -> 8 -> 9 -> 10");

        String text3 = "AabcdeZ";
        StdOut.print("\nProof 3: ");
        regularExpressionMatcherWithProof2.recognizes(text3);
        StdOut.println("Expected: 0 -> 1 -> 2 -> 3 -> 7 -> 8 -> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 1 -> 2 -> 3 -> 7 -> 8 -> 1 -> 2 -> 3 -> 7 -> 8 -> 1 -> 2 -> 3 -> 7 -> 8 -> 9 -> 10");

        String pattern3 = "A[^A-Z0]+ZZ";
        Exercise22_Proof.RegularExpressionMatcherWithProof regularExpressionMatcherWithProof3 =
                proof.new RegularExpressionMatcherWithProof(pattern3);
        String text4 = "AbcZZ";
        StdOut.print("\nProof 4: ");
        regularExpressionMatcherWithProof3.recognizes(text4);
        StdOut.println("Expected: 0 -> 1 -> 2 -> 3 -> 7 -> 8 -> 1 -> 2 -> 3 -> 7 -> 8 -> 9 -> 10 -> 11");

        String pattern4 = "A[^A-Z0]*ZZ";
        Exercise22_Proof.RegularExpressionMatcherWithProof regularExpressionMatcherWithProof4 =
                proof.new RegularExpressionMatcherWithProof(pattern4);
        String text5 = "AZZ";
        StdOut.print("\nProof 5: ");
        regularExpressionMatcherWithProof4.recognizes(text5);
        StdOut.println("Expected: 0 -> 1 -> 8 -> 9 -> 10 -> 11");

        String text6 = "Abcdef123ZZ";
        StdOut.print("\nProof 6: ");
        regularExpressionMatcherWithProof4.recognizes(text6);
        StdOut.println("Expected: 0 -> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 1 -> 2 -> 3 -> 7 -> 8 " +
                "-> 9 -> 10 -> 11");

        String pattern5 = "A([^A-Z0]|[^a-f])+[^a-f]Z";
        Exercise22_Proof.RegularExpressionMatcherWithProof regularExpressionMatcherWithProof5 =
                proof.new RegularExpressionMatcherWithProof(pattern5);
        String text7 = "ABgZ";
        StdOut.print("\nProof 7: ");
        regularExpressionMatcherWithProof5.recognizes(text7);
        StdOut.println("Expected: 0 -> 1 -> 10 -> 11 -> 12 -> 15 -> 16 -> 17 -> 18 -> 19 -> 20 -> 23 -> 24 -> 25");

        String text8 = "ABCDEFGagZ";
        StdOut.print("\nProof 8: ");
        regularExpressionMatcherWithProof5.recognizes(text8);
        StdOut.println("Expected: 0 -> 1 -> 10 -> 11 -> 12 -> 15 -> 16 -> 17 -> " +
                "1 -> 10 -> 11 -> 12 -> 15 -> 16 -> 17 -> " +
                "1 -> 10 -> 11 -> 12 -> 15 -> 16 -> 17 -> " +
                "1 -> 10 -> 11 -> 12 -> 15 -> 16 -> 17 -> " +
                "1 -> 10 -> 11 -> 12 -> 15 -> 16 -> 17 -> " +
                "1 -> 10 -> 11 -> 12 -> 15 -> 16 -> 17 -> " +
                "1 -> 2 -> 3 -> 4 -> 8 -> 9 -> 16 -> 17 -> " +
                "18 -> 19 -> 20 -> 23 -> 24 -> 25");

        String text9 = "ABZ";
        StdOut.print("\nProof 9: ");
        regularExpressionMatcherWithProof5.recognizes(text9);
        StdOut.println("Expected: Text was not recognized by the DFA");
    }
}


Question: Given a example of a uniquely decodable code that is not prefix-free.

Answer:
5.5.2

Example of a uniquely decodable code that is not prefix-free:
Any suffix-free code is uniquely decodable.

Example: { 0, 01, 011, 0111 }


Question: Give an example of a uniquely decodable code that is not prefix free or suffix free.

Answer:
5.5.3

Example of a uniquely decodable code that is not prefix-free or suffix-free:
{ 0011, 011, 11, 1110 } or { 01, 10, 011, 110 }


Question: Are { 1, 100000, 00 } and { 01, 1001, 1011, 111, 1110 } uniquely decodable? If not, find a string with two encodings.

Answer:
5.5.4

{ 1, 100000, 00 } is uniquely decodable.

{ 01, 1001, 1011, 111, 1110 } is not uniquely decodable.
The string 11101111001 can be decoded both as 1110-111-1001 and 111-01-1110-01.


Question: Use RunLength on the file q64x96.bin from the booksite. How many bits are there in the compressed file?

Answer:
5.5.5

The file q128x192.bin was not found anywhere on the booksite or in the data URL https://algs4.cs.princeton.edu/code/algs4-data.zip
However, the file q64x96.bin exists in the booksite on the aforementioned algs4-data.zip and on the hidden URL https://algs4.cs.princeton.edu/55compression/q64x96.bin .

In the uncompressed file there are 6144 bits.
In the compressed file there are 2296 bits.

Commands used:
% javac -cp algs4.jar BinaryDump.java
% javac -cp algs4.jar RunLengthEncoding.java
% java -cp algs4.jar:. RunLengthEncoding - < q64x96.bin | java -cp algs4.jar:. BinaryDump 0


Question: How many bits are needed to encode N copies of the symbol a (as a function of N)? N copies of the sequence abc?

Answer:
5.5.6

Copies of symbol a:

% more 5.5_input_1a.txt
a

% more 5.5_input_2a.txt
aa

% more 5.5_input_3a.txt
aaa

% more 5.5_input_20a.txt
aaaaaaaaaaaaaaaaaaaa

*** Run-length encoding ***

% java -cp algs4.jar:. RunLengthEncoding - < 5.5_input_1a.txt | java -cp algs4.jar:. BinaryDump 0
32 bits

% java -cp algs4.jar:. RunLengthEncoding - < 5.5_input_2a.txt | java -cp algs4.jar:. BinaryDump 0
64 bits

% java -cp algs4.jar:. RunLengthEncoding - < 5.5_input_3a.txt | java -cp algs4.jar:. BinaryDump 0
96 bits

% java -cp algs4.jar:. RunLengthEncoding - < 5.5_input_20a.txt | java -cp algs4.jar:. BinaryDump 0
640 bits

Bits needed to encode N copies of the symbol a: 32N

*** Huffman encoding ***

% java -cp algs4.jar:. edu.princeton.cs.algs4.Huffman - < 5.5_input_1a.txt | java -cp algs4.jar:. BinaryDump 0
56 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.Huffman - < 5.5_input_2a.txt | java -cp algs4.jar:. BinaryDump 0
56 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.Huffman - < 5.5_input_3a.txt | java -cp algs4.jar:. BinaryDump 0
56 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.Huffman - < 5.5_input_20a.txt | java -cp algs4.jar:. BinaryDump 0
72 bits

Number of a symbols - bits needed to encode
1-5: 56
6-13 : 64
14-21: 72
22-29: 80
30-37: 88
38: 96

Bits needed to encode N copies of the symbol a: 56 + ((N - 6) / 8 + 1) * 8

*** LZW encoding ***

% java -cp algs4.jar:. edu.princeton.cs.algs4.LZW - < 5.5_input_1a.txt | java -cp algs4.jar:. BinaryDump 0
24 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.LZW - < 5.5_input_2a.txt | java -cp algs4.jar:. BinaryDump 0
40 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.LZW - < 5.5_input_3a.txt | java -cp algs4.jar:. BinaryDump 0
40 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.LZW - < 5.5_input_20a.txt | java -cp algs4.jar:. BinaryDump 0
88 bits

Number of a symbols - bits needed to encode
1: 24
2-3: 40
4-6: 48
7-10: 64
11-15: 72 bits
16-21: 88 bits
22-28: 96 bits
29: 112 bits

                                                      i<=N
Bits needed to encode N copies of the symbol a: 16 +   E        8 if j % 2 == 1
                                                               16 if j % 2 == 0
                                                    i=1, j=1
                                                    i+=j; j++

Copies of symbol abc:

% more 5.5_input_1abc.txt
abc

% more 5.5_input_2abc.txt
abcabc

% more 5.5_input_3abc.txt
abcabcabc

% more 5.5_input_20a.txt
abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc

*** Run-length encoding ***

% java -cp algs4.jar:. RunLengthEncoding - < 5.5_input_1abc.txt | java -cp algs4.jar:. BinaryDump 0
96 bits

% java -cp algs4.jar:. RunLengthEncoding - < 5.5_input_2abc.txt | java -cp algs4.jar:. BinaryDump 0
192 bits

% java -cp algs4.jar:. RunLengthEncoding - < 5.5_input_3abc.txt | java -cp algs4.jar:. BinaryDump 0
288 bits

% java -cp algs4.jar:. RunLengthEncoding - < 5.5_input_20abc.txt | java -cp algs4.jar:. BinaryDump 0
1920 bits

Bits needed to encode N copies of the sequence abc: 96N

*** Huffman encoding ***

% java -cp algs4.jar:. edu.princeton.cs.algs4.Huffman - < 5.5_input_1abc.txt | java -cp algs4.jar:. BinaryDump 0
72 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.Huffman - < 5.5_input_2abc.txt | java -cp algs4.jar:. BinaryDump 0
72 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.Huffman - < 5.5_input_3abc.txt | java -cp algs4.jar:. BinaryDump 0
80 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.Huffman - < 5.5_input_20abc.txt | java -cp algs4.jar:. BinaryDump 0
168 bits

Number of abc sequences - bits needed to encode
1-2: 72
3: 80
4-5: 88
6-7: 96
8: 104
9-10: 112
11: 120
12-13: 128
14-15: 136
16: 144
17-18: 152
19: 160
20-21: 168
22-23: 176
24: 184

                                                            i<=N
Bits needed to encode N copies of the sequence abc: 64 +     E   8
                                                         i=1, j=2
                                                         i+=j; j=2 if j == 1 || (i - 4) % 8 == 0 || (i - 6) % 8 == 0
                                                               j=1 [else]

*** LZW encoding ***

% java -cp algs4.jar:. edu.princeton.cs.algs4.LZW - < 5.5_input_1abc.txt | java -cp algs4.jar:. BinaryDump 0
48 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.LZW - < 5.5_input_2abc.txt | java -cp algs4.jar:. BinaryDump 0
72 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.LZW - < 5.5_input_3abc.txt | java -cp algs4.jar:. BinaryDump 0
88 bits

% java -cp algs4.jar:. edu.princeton.cs.algs4.LZW - < 5.5_input_20abc.txt | java -cp algs4.jar:. BinaryDump 0
232 bits

Number of abc sequences - bits needed to encode
1: 48
2: 72
3: 88
4: 96
5: 112
6: 120
7: 136
8: 144
9-10: 160
11: 168
12-13: 184
14-15: 192
16-17: 208
18-19: 216
20-21: 232
22-23: 240

                                                     i<=N
Bits needed to encode N copies of the sequence abc:    E       48 if i == 1
                                                               24 [else] if i == 2
                                                               16 [else] if k == 1
                                                                8 [else] if k == 2
                                                     i=1, j=1, k=1
                                                     i+=j; k=1 if k == 2; j=1 if i < 9 || i == 11
                                                           k=2 if k == 1; j=2 [else]


Question: Give the result of encoding the strings ab, abab, ababab, abababab, ... (strings consisting of N repetitions of ab) with run-length, Huffman, and LZW encoding. What is the compression ratio as a function of N?

Answer:
Let the input be `(ab)^N`, so the uncompressed input has `2N` 8-bit characters, or `16N` bits.

Run-length encoding in the algs4 binary format emits `64N + 8` bits for this alternating input. Its compression ratio is therefore

`(64N + 8) / (16N) = 4 + 1/(2N)`.

So run-length encoding expands the data by about 4x.

Huffman coding has two symbols with equal frequency, so the data portion uses one bit per input character, or `2N` data bits. The algs4 format also writes a trie for the two leaves and a 32-bit character count, for `2N + 51` bits before byte padding. With byte padding:

`8 * ceil((2N + 51) / 8)` bits,

and the compression ratio is

`8 * ceil((2N + 51) / 8) / (16N)`,

which tends to `1/8`.

LZW parses the alternating string into longer and longer repeated phrases. If `c(N)` is the number of LZW phrases produced by the greedy parse of `(ab)^N`, algs4 writes `c(N) + 1` fixed-width 12-bit codes including EOF, rounded to a byte boundary:

`8 * ceil(12(c(N) + 1) / 8)` bits.

Here `c(N) = Theta(sqrt(N))`, so the LZW compression ratio is `Theta(1 / sqrt(N))`. For example, the measured algs4 outputs are 40, 48, 64, 72, 160, and 352 bits for `N = 1, 2, 3, 4, 20, 100`, respectively; for `N = 100`, the ratio is `352 / 1600 = 22%`, not `352%`.