1. 程式人生 > >字符串----最短摘要生成

字符串----最短摘要生成

如果 urn new 多次 image 字符 contain 空格 ron

題目:Alibaba筆試題,給定一段產品的英文描述,包含M個英文單詞,每個英文單詞以空格分隔,無其他標點符號;再給定N個英文單詞關鍵字,請說明思路並編程實現方法。String extractSummary(String description,String[] key words)目標是找出此產品描述中包含N個關鍵字(每個關鍵詞至少出現一次)的長度最短的子串,作為產品簡介輸出。(不限編程語言)20分。

思路一:

直接暴力解法,循環暴力破解,每次判斷關鍵字是否全部包含,然後不斷更新邊界。

思路二:

先來看看這些序列(w為英文單詞,q為關鍵字):

w0,w1,w2,w3,q0,w4,w5,q1
,w6,w7,w8,q0,w9,q1

問題在於,一次性掃描確定邊界這不太現實,肯定要多次掃描,不斷更新邊界,這裏只說每個關鍵字必須要出現一次以上,並沒有說要順序出現。先第一次掃描,掃描到第一個關鍵字,從第一個位置w0處將掃描到q0處:

w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

然後再從q0處開始掃描,直到出現第一個包含所有關鍵字的序列,並記錄邊界:

w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

然後掃描的位置繼續往後移動,移動到q1,這樣包含的序列中就少了q0,那麽就從q1開始掃描,這樣就可以找到下一個包含所有關鍵字的序列,即從q1掃描到了q0處,這兒也要更新邊界:

w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

然後,在繼續往後掃描,定位到下一個關鍵字q0,繼續往後掃描,如此循環往後掃描,直至掃描完成,那麽邊界長度就是最小的了。

代碼:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class 最短摘要 {

    public static void main(String[] args) {
         solve1(new String[]{"a", "b", "c", "seed", "h", "e", "f", "c", "c", "seed", "e", "f", "seed", "c"}, 
                 
new String[]{"c", "e"}); solve2(new String[]{"a", "b", "c", "seed", "c", "e", "f", "c", "c", "seed", "e", "f", "seed", "c"}, new String[]{"c", "c", "e", "f"}); solve2(new String[]{"a", "b", "a", "a", "b", "c", "d", "h", "e", "f", "f"}, new String[]{"b", "c", "d"}); } // 暴力破解法 public static void solve1(String[] w, String[] q) { int length = Integer.MAX_VALUE; int begin = -1; int end = -1; for (int i = 0; i < w.length; i++) { // 求以i開頭包含所有關鍵字的序列 for (int j = i+1; j < w.length; j++) { // 如果全部關鍵字已經再seq中。 if (containsAll(q,w,i,j)) { // 判斷當前這個序列是不是較短的序列 // System.out.println(seq); if (j-i+1<length) { length = j-i+1; begin = i; end = j; } break; } } } print(w,begin,end); } /** * 這種解法解決了keys關鍵字中有重復的現象 * @param w * @param keys */ public static void solve2(String[] w, String[] keys) { Arrays.sort(keys); // begin和end用於在找到更短的包含全部關鍵字的子數組時更新 int begin = -1; int end = -1; int j = -1; // 上一次囊括了所有關鍵字的右邊界 int minLen = Integer.MAX_VALUE; for (int i = 0; i < w.length; i++) { // 如果i位置是關鍵字,求以i開頭包含所有關鍵字的序列 String word1 = w[i]; int index = Arrays.binarySearch(keys, word1); if (-1==index) { continue; }else { // i是一個關鍵字 // 如果已經全部找到 if (j<w.length&&j>=i&&containsAll(keys, w, i, j)) { if (j-i+1<minLen) { // 更新 minLen = j-i+1; begin = i; end = j; } continue; } } if (j==-1) { j = j+1; // j值初始化 } while(j<w.length){ String word2 = w[j]; // 文章單詞 int index1 = Arrays.binarySearch(keys, word2); if (-1==index1) { j++; continue; }else { // 找到關鍵字 這裏應該是第一次掃描的包含所有關鍵字的 然後繼續for循環不斷更新邊界 if (containsAll(keys, w, i, j)) { //全部到齊 if (j - i + 1 < minLen) {// 更新 minLen = j - i + 1; begin = i; end = j; } break; }else { j++; } } } } print(w, begin, end); } private static boolean containsAll(String[] keywords, String[] w, int i, int j) { Map<String, Integer> map = new HashMap<>(); for (int k = 0; k < keywords.length; k++) { String key = keywords[k]; if (map.get(key)==null) { map.put(key, 1); }else { map.put(key, map.get(key)+1); } } Map<String, Integer> map2 = new HashMap<>(); for (int k = i; k <= j; k++) { String key = w[k]; if (map2.get(key)==null) { map2.put(key, 1); }else { map2.put(key, map2.get(key)+1); } } for(Map.Entry<String, Integer> e:map.entrySet()){ if (map2.get(e.getKey())==null||map2.get(e.getKey())<e.getValue()) { return false; } } return true; } private static void print(String[] w, int begin, int end) { System.out.println(begin+" "+end); for (int i = begin; i <=end; i++) { System.out.print(w[i]+" "); } System.out.println(); } }

結果:

  技術分享圖片

字符串----最短摘要生成