<p>Using for reference, Aho and Corasick, <em>Efficient string matching: an aid to bibliographic search</em> (<em>Communications of the ACM</em>, 18(6):333&ndash;340, 1975) (<a href="http://dl.acm.org/citation.cfm?doid=360825.360855" rel="nofollow">PDF</a>).</p>

<p>Algorithm 2 is mostly creating a <a href="http://en.wikipedia.org/wiki/Trie" rel="nofollow">trie</a> or "keyword tree" in the paper.</p>

<p><strong>Important Note</strong>: They make the assumption that $g(s, a) = \texttt{fail}$ if either $a$ is undefined, or  $g(s, a)$ hasn't been defined yet. You can think of this function as an edge, it either points to the next state or returns $\texttt{fail}$. Assume evaluating and assigning to functions, such as $g$ or $output$, takes constant time.</p>

<p><strong>Example</strong>:</p>

<p>Let's consider the intuition for a single keyword $x$. Use the last graph on page 335 with his, hers and she. Let's add "hello" and verify that it takes linear time in the length. We can generalize from there.</p>

<p>For this example, let $y = \text{hello}$.</p>

<p>$s = 0$, the initial state. First, we find out that $g(0, \text{h}) = 1$ so we
set $s = 1$. Next we check $g(1, \text{e})$, which takes us to $s = 2$.</p>

<p>Now $g(2, \textit{l}) = \texttt{fail}$, there is no edge for $\textit{l}$, we have to create a state, $s = 10$ and set $g(2, \textit{l}) = 10$. State $10$ corresponds to the string $\text{hel}$.</p>

<p>Again $g(10, \textit{l}) = \texttt{fail}$, we create a new state $s = 11 \text{(hell)}$. The same happens for $\textit{o}$ : $g(11, \textit{o}) = \texttt{fail}$, make a new state $12 \text{(hello)}$.</p>

<p>We've finished $\text{hello}$, as a last step we set $output(12) = \text{hello}$.  </p>

<p><strong>Rough Analysis:</strong></p>

<p>Calling $g(s,a)$, assigning values, and creating new states are constant time. Since we perform a constant number of each operation per letter, the complexity is $\mathcal{O}(|\text{y}|)$. </p>

<p>Algorithm 2 does this for each key word. Notice that the same bound holds for each keyword added, <em>regardless of what $g(s,a)$ returns for each letter</em>. Then the total time complexity is $\mathcal{O}(\displaystyle \sum_i^k{|y_i|})$, proportional to the sum of the length of the keywords.</p>

<p>The algorithm also sets a self-loop for any unused symbols, or $g(0, a) = 0$ for all $a$ that weren't the first letter of a keyword. We only need to consider letters in the set of keywords, so this step is still bounded by the sum length.</p>

CC BY-SA 3.0
2014-07-16T18:42:17.493Z
2014-07-17T02:17:20.303Z
2014-07-17T02:17:20.303Z
Michael Xu
<p>The original paper's analysis of this, as far as I can tell is this:</p>

<p>"THEOREM 3. Algorithm 2 requires time linearly proportional to the sum of the lengths of the keywords. 
PROOF. Straightforward."</p>

<p>But it's not at all obvious.</p>

<ds.algorithms><ds.data-structures><time-complexity><string-matching>
Why does the construction step of Aho-Corasick take linear time in the number of nodes?
James Shapiro
# Why does the construction step of Aho-Corasick take linear time in the number of nodes?

(Asked by: username_0 on 2014-05-11)

The original paper's analysis of this, as far as I can tell is this:

"THEOREM 3. Algorithm 2 requires time linearly proportional to the sum of the lengths of the keywords.
PROOF. Straightforward."

But it's not at all obvious.

**Tags:** ds.algorithms, ds.data-structures, time-complexity, string-matching


---

## 1 answers

### Answer by username_1 on 2014-07-16. Score: 1

Using for reference, Aho and Corasick, *Efficient string matching: an aid to bibliographic search* (*Communications of the ACM*, 18(6):333–340, 1975) ([PDF](http://dl.acm.org/citation.cfm?doid=360825.360855)).

Algorithm 2 is mostly creating a [trie](http://en.wikipedia.org/wiki/Trie) or "keyword tree" in the paper.

**Important Note**: They make the assumption that $g(s, a) = \texttt{fail}$ if either $a$ is undefined, or $g(s, a)$ hasn't been defined yet. You can think of this function as an edge, it either points to the next state or returns $\texttt{fail}$. Assume evaluating and assigning to functions, such as $g$ or $output$, takes constant time.

**Example**:

Let's consider the intuition for a single keyword $x$. Use the last graph on page 335 with his, hers and she. Let's add "hello" and verify that it takes linear time in the length. We can generalize from there.

For this example, let $y = \text{hello}$.

$s = 0$, the initial state. First, we find out that $g(0, \text{h}) = 1$ so we
set $s = 1$. Next we check $g(1, \text{e})$, which takes us to $s = 2$.

Now $g(2, \textit{l}) = \texttt{fail}$, there is no edge for $\textit{l}$, we have to create a state, $s = 10$ and set $g(2, \textit{l}) = 10$. State $10$ corresponds to the string $\text{hel}$.

Again $g(10, \textit{l}) = \texttt{fail}$, we create a new state $s = 11 \text{(hell)}$. The same happens for $\textit{o}$ : $g(11, \textit{o}) = \texttt{fail}$, make a new state $12 \text{(hello)}$.

We've finished $\text{hello}$, as a last step we set $output(12) = \text{hello}$.

**Rough Analysis:**

Calling $g(s,a)$, assigning values, and creating new states are constant time. Since we perform a constant number of each operation per letter, the complexity is $\mathcal{O}(|\text{y}|)$.

Algorithm 2 does this for each key word. Notice that the same bound holds for each keyword added, *regardless of what $g(s,a)$ returns for each letter*. Then the total time complexity is $\mathcal{O}(\displaystyle \sum\_i^k{|y\_i|})$, proportional to the sum of the length of the keywords.

The algorithm also sets a self-loop for any unused symbols, or $g(0, a) = 0$ for all $a$ that weren't the first letter of a keyword. We only need to consider letters in the set of keywords, so this step is still bounded by the sum length.


---

