【字符串】最短摘要问题

给定一段产品的英文描述,包含M个英文单词,每个单词以空格分隔。无其他标点符号; 再给定N个英文单词做关键词。

编程实现方法,目标是按照此产品的描述包含N个关键字的长度最短的子串,作为产品简介输出。 每个关键词至少出现一次。

方法1:暴力法

利用双层循环,从头遍历M个英文单词,如果N个关键词均包含在keyFound[i,j]中,且如果这段距离是最短的,就更新begin,end,直至扫描完全部M个英文单词。打印最短的产品简介。

方法2:尺取法

尺取法通常是指对数组保存一对下标(起点,终点),然后根据实际情况交替推进两个端点直到得出答案的方法。

扫描M个英文单词,二叉搜索查找该处单词是否在关键词中,如果不在就continue,如果在,且右边界大于i且全部找到就更新最短距离,再继续走循环直到结束。

第一次右边界从i+1走,查找接下来未找到的关键词,同上。需要考虑在关键词有重复的情况。

 1 private static void solve1(String[] src, String[] keys) {
 2 
 3         int minlength = Integer.MAX_VALUE;
 4         int begin = -1;
 5         int end = -1;
 6         for (int i = 0; i < src.length; i++) {
 7             for (int j = i + 1; j < src.length; j++) {
 8 
 9                 if (containsAll(src, keys, i, j)) {// 如果该段包含全部的关键词
10 
11                     if (j - i + 1 < minlength) {// 且为距离最短的一段
12                         minlength = j - i + 1;
13                         begin = i;
14                         end = j;
15                     }
16                     break;
17                 }
18             }
19         }
20         print(src, begin, end);
21     }
暴力法

 

 1   public static void solve2(String[] src, String[] keys) {
 2             Arrays.sort(keys);
 3             int j=-1;
 4             int begin=-1;
 5             int end=-1;
 6             int minlength=Integer.MAX_VALUE;
 7             for (int i = 0; i < src.length; i++) {
 8                 String word=src[i];
 9                 int index=Arrays.binarySearch(keys, word);
10                 if(index==-1){
11                     continue;
12                 }else{//i处是一个关键字
13                     if(j<src.length && j>=i &&containsAll(src, keys, i, j)){//所有关键词全部找到
14                         if(minlength>j-i+1){
15                             minlength=j-i+1;
16                             begin=i;
17                             end=j;
18                         }
19                         continue;
20                     }
21                     
22                 }
23                 if(j==-1)
24                     j=i+1;
25                 while(j<src.length){
26                         String word1=src[i];
27                         int index1=Arrays.binarySearch(keys, word1);
28                         if(index1==-1){
29                             j++;
30                         }else{//j处是一个关键字
31                             if(containsAll(src, keys, i, j)){//所有关键词全部找到
32                                 if(minlength>j-i+1){
33                                     minlength=j-i+1;
34                                     begin=i;
35                                     end=j;
36                                 }
37                                 break;//退出while循环
38                             }else{//还没找到左右,j继续走
39                                 j++;
40                                 }
41                             }
42                             
43                         }
44             }
45             print(src, begin, end);
46       }
尺取法

 

判断该段是否包含全部关键词 思路:

利用hash映射,将关键词keys的数组加入如果之前没出现过,就将其加入map,如果出现过就将其value+1;

然后在利用第二个map2,扫描src[i,j]段单词数组,同上操作;

最后扫描关键词的map,如果map2的那段中不包含关键词中,或者包含关键词的个数不相等 就return false;

 1 /**
 2      * 
 3      * @param src
 4      * @param keys
 5      * @param i
 6      * @param j
 7      * @return
 8      */
 9     private static boolean containsAll(String[] src, String[] keys, int i, int j) {
10         Map<String, Integer> map = new HashMap<>();
11         for (int k = 0; k < keys.length; k++) {
12             String key = keys[k];
13             if (map.get(key) == null) {
14                 map.put(key, 1);
15             } else {// 如果已经存在,就将value+1
16                 map.put(key, map.get(key) + 1);
17             }
18 
19         }
20         Map<String, Integer> map2 = new HashMap<>();
21         for (int k = i; k <= j; k++) {
22             String key = src[k];
23             if (map2.get(key) == null) {
24                 map2.put(key, 1);
25             } else {// 如果已经存在,就将value+1
26                 map2.put(key, map2.get(key) + 1);
27             }
28 
29         }
30         for (Map.Entry<String, Integer> e : map.entrySet()) {
31             if (map2.get(e.getKey()) == null
32                     || map2.get(e.getKey()) < e.getValue()) {
33                 return false;
34             }
35 
36         }
37 
38         return true;
39     }
辅助方法containsAll

 

打印结果数组

1     private static void print(String[] src, int begin, int end) {
2 
3         System.out.println(begin + " " + end);
4         for (int i = begin; i <= end; i++) {
5             System.out.print(src[i] + " ");
6         }
7         // System.out.println();
8 
9     }
print

 

测试代码

1 public static void main(String[] args) {
2         String[] s1 = { "a", "b", "c", "seed", "h", "e", "f", "c", "c", "seed",
3                 "e", "f", "seed", "c" };
4         String[] s2 = { "c", "e","c" };
5     //    solve1(s1, s2);
6         solve2(s1,s2);
7     }
测试

 

posted on 2021-01-28 20:35  丁不煮  阅读(100)  评论(0编辑  收藏  举报

导航