《算法》第六章部分程序 part 4

▶ 书中第六章部分程序,包括在加上自己补充的代码,利用后缀树查找最长重复子串、查找最大重复子串并输出其上下文(Key word in context,KWIC)、求两字符串的最长公共子串

● 利用后缀树查找最长重复子串

 1 package package01;
 2 
 3 import edu.princeton.cs.algs4.StdIn;
 4 import edu.princeton.cs.algs4.StdOut;
 5 import edu.princeton.cs.algs4.SuffixArrayX;
 6 
 7 public class class01
 8 {
 9     private class01() {}
10 
11     public static String lrs(String text)
12     {
13         int n = text.length();
14         SuffixArrayX sa = new SuffixArrayX(text);
15         String lrs = "";
16         for (int i = 1; i < n; i++)                             // 遍历一次,记录最长公共前缀
17         {
18             int length = sa.lcp(i);
19             if (length > lrs.length())
20                 lrs = text.substring(sa.index(i), sa.index(i) + length);
21         }
22         return lrs;
23     }
24 
25     public static void main(String[] args)
26     {
27         String text = StdIn.readAll().replaceAll("\s+", " ");  // 空白字符全部换成 ' '
28         StdOut.println("'" + lrs(text) + "'");
29     }
30 }

● 利用后缀树查找最大重复子串并输出其上下文(Key word in context,KWIC)

 1 package package01;
 2 
 3 import edu.princeton.cs.algs4.In;
 4 import edu.princeton.cs.algs4.StdIn;
 5 import edu.princeton.cs.algs4.StdOut;
 6 import edu.princeton.cs.algs4.SuffixArrayX;
 7 
 8 public class class01
 9 {
10     private class01() {}
11 
12     public static void main(String[] args)
13     {
14         In in = new In(args[0]);                                                    // 命令参数,分别为输入文件和需要输出的上下文字符数量
15         int context = Integer.parseInt(args[1]);
16         String text = in.readAll().replaceAll("\s+", " ");
17         int n = text.length();
18         SuffixArrayX sa = new SuffixArrayX(text);
19 
20         for (; StdIn.hasNextLine(); StdOut.println())
21         {
22             String query = StdIn.readLine();
23             for (int i = sa.rank(query); i < n; i++)
24             {
25                 int from1 = sa.index(i), to1 = Math.min(n, from1 + query.length()); // 取 index[i] 的头和尾,要求它和 query 不同
26                 if (!query.equals(text.substring(from1, to1)))
27                     break;
28                 int from2 = Math.max(0, sa.index(i) - context), to2 = Math.min(n, sa.index(i) + context + query.length());
29                 StdOut.println(text.substring(from2, to2));                         // 向前向后各取 context 个字符
30             }
31         }
32     }
33 }

● 利用后缀树求两字符串的最长公共子串

 1 package package01;
 2 
 3 import edu.princeton.cs.algs4.In;
 4 import edu.princeton.cs.algs4.StdOut;
 5 import edu.princeton.cs.algs4.SuffixArrayX;
 6 
 7 public class class01
 8 {
 9     private class01() {}
10 
11     private static String lcp(String s, int p, String t, int q)     // 返回 s[p] 和 t[q] 开始的两个子串的最大公共子串
12     {
13         int n = Math.min(s.length() - p, t.length() - q);
14         for (int i = 0; i < n; i++)                                 // 逐元素比较就好了,返回保持相等的最长子串
15         {
16             if (s.charAt(p + i) != t.charAt(q + i))
17                 return s.substring(p, p + i);
18         }
19         return s.substring(p, p + n);
20     }
21 
22     private static int compare(String s, int p, String t, int q)    // 比较两个后缀元素的字典序,用于判断哪个后缀元素要改用下一个
23     {
24         int n = Math.min(s.length() - p, t.length() - q);
25         for (int i = 0; i < n; i++)
26         {
27             if (s.charAt(p + i) != t.charAt(q + i))
28                 return s.charAt(p + i) - t.charAt(q + i);
29         }
30         if (s.length() - p < t.length() - q)
31             return -1;
32         else if (s.length() - p > t.length() - q)
33             return +1;
34         return  0;
35     }
36 
37     public static String lcs(String s, String t)
38     {
39         SuffixArrayX suffix1 = new SuffixArrayX(s), suffix2 = new SuffixArrayX(t);
40         String lcs = "";
41         for (int i = 0, j = 0; i < s.length() && j < t.length();)   // 两个后缀数组比较 O(s.length() + t.length()) 次
42         {                                                           // 每次检查两个后缀元素的最长相等子串
43             int p = suffix1.index(i), q = suffix2.index(j);         // 一旦找到不相等的元素,字典序靠前的元素就取下一个后缀元素继续比较
44             String x = lcp(s, p, t, q);
45             if (x.length() > lcs.length())
46                 lcs = x;
47             if (compare(s, p, t, q) < 0)
48                 i++;
49             else
50                 j++;
51         }
52         return lcs;
53     }
54 
55     public static void main(String[] args)
56     {
57         In in1 = new In(args[0]), in2 = new In(args[1]);
58         String s = in1.readAll().trim().replaceAll("\s+", " ");
59         String t = in2.readAll().trim().replaceAll("\s+", " ");
60         StdOut.println("'" + lcs(s, t) + "'");
61     }
62 }
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9945104.html