【字符串】最短摘要问题
给定一段产品的英文描述,包含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 }
打印结果数组
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 }
测试代码
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 }