/// <summary>
        /// Returns Aho-Corasic tree for a set of patterns and alphabet parameters
        /// </summary>
        /// <returns></returns>
        public static AhoCorasickTree GetAhoCorasickTree(this char[][] patterns, char minChar, char maxChar)
        {
            var tree = new AhoCorasickTree(patterns.Sum(p => p.Length) + 1, maxChar - minChar + 1, minChar);

            foreach (var pattern in patterns)
            {
                tree.AddString(pattern);
            }
            return(tree);
        }
        /// <summary>
        /// Counts the number of matchings of patterns in a given text
        /// tree must be built with a set of distinct patterns!
        /// </summary>
        public static long CountMatches(this AhoCorasickTree tree, char[] text)
        {
            if (text == null || text.Length == 0)
            {
                return(0);
            }

            long res = 0;

            var dp = new int[tree.Size];

            dp.Fill(-1);
            dp[0] = 0;

            var st    = 0;
            var stack = new int[tree.Size];
            int sz    = 0;

            for (int i = 0; i < text.Length; i++)
            {
                st = tree.GetNextState(st, (char)(text[i] - tree.MinChar));

                int u = st;
                while (dp[u] == -1)
                {
                    stack[sz++] = u;
                    u           = tree.GetSuffixLink(u);
                }

                while (sz > 0)
                {
                    var cur = stack[--sz];
                    dp[cur] = (tree.IsLeaf(cur) ? 1 : 0) + dp[u];
                    u       = cur;
                }

                res += dp[st];
            }

            return(res);
        }