zoukankan      html  css  js  c++  java
  • 编程之美3.5最短摘要生成

      Alibaba笔试题:给定一段产品的英文描述,包含M个英文字母,每个英文单词以空格分隔,无其他标点符号;再给定N个英文单词关键字,请说明思路并编程实现方法String extractSummary(String description,String[] key words),目标是找出此产品描述中包含N个关键字(每个关键词至少出现一次)的长度最短的子串,作为产品简介输出。(不限编程语言)20分。

      这道笔试题和编程之美最短摘要生成的方法类似,我用java实现了这个方法。

      先来看看这些序列:

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

         问题在于,如何一次把所有的关键词都扫描到,并且不遗漏。扫描肯定是无法避免的,但是如何把两次扫描的结果联系起来呢?这是一个值得考虑的问题。

         沿用前面的扫描方法,再来看看。第一次扫描的时候,假设需要包含所有的关键词,从第一个位置w0处将扫描到w6处:

    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

         然后把第一个被扫描的位置继续往后面移动一格,这样包含的序列中将减少了关键词q0。那么,我们便可以把第二个扫描位置往后移,这样就可以找到下一个包含所有关键词的序列。即从w4扫描到w9处,便包含了q1,q0:

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

         这样,问题就和第一次扫描时碰到的情况一样了。依次扫描下去,在w中找出所有包含q的序列,并且找出其中的最小值,就可得到最终的结果。

         编程之美上给出了如下参考代码:

    int nTargetLen = N + 1; // 设置目标长度为总长度+1  
    int pBegin = 0; // 初始指针
    int pEnd = 0; // 结束指针
    int nLen = N; // 目标数组的长度为N
    int nAbstractBegin = 0; // 目标摘要的起始地址
    int nAbstractEnd = 0; // 目标摘要的结束地址

    while(true)
    {
    // 假设未包含所有的关键词,并且后面的指针没有越界,往后移动指针
    while(!isAllExisted() && pEnd < nLen)
    {
    pEnd++;
    }

    // 假设找到一段包含所有关键词信息的字符串
    while(isAllExisted())
    {
    if(pEnd – pBegin < nTargetLen)
    {
    nTargetLen = pEnd – pBegin;
    nAbstractBegin = pBegin;
    nAbstractEnd = pEnd – 1;
    }
    pBegin++;
    }
    if(pEnd >= N)
    Break;
    }

      以下是我写的java实现代码。
         使用HashMap将关键字映射到数字,减少字符串比较,能进一步提高效率。使用数组保存关键字被访问到的次数,用来判断是否包含全部关键字。

    package com.flyoung;

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

    public class Abstract {
    /*
    * 编程之美 最短摘要生成
    *
    */

    private int[] keywordsArray; //记录关键字被访问次数的数组
    private int pBegin=0;//查找起始点
    private int pEnd=0;//查找终点
    private int abstractBegin=0;//摘要起始点
    private int abstractEnd=0;//摘要终点
    private int targetLen;//摘要最小长度
    private Map<String,Integer> map;//将关键字映射成数字

    public Abstract(String[] keywords){
    int len = keywords.length;
    this.keywordsArray = new int[len];
    this.map = keywordsMap(keywords);
    }
    public String extractSummary(String description,String[] keywords){
    String[] array = description.split(" ");//将字符串转化为数组
    return extract(array,keywords);
    }
    //实际的抽取函数
    public String extract(String[] description,String[] keywords){
    String summary = "";
    int nLen = description.length;
    targetLen = nLen+1;
    while(true){
    while(!isAllExisted()&&pEnd<nLen){
    if(this.map.get(description[pEnd])!=null){
    setKeywordsArray(keywordsArray,this.map.get(description[pEnd]),0);
    }
    pEnd++;
    }
    while(isAllExisted()){
    if(pEnd-pBegin<targetLen){
    targetLen = pEnd-pBegin;
    abstractBegin = pBegin;
    abstractEnd = pEnd-1;
    }
    if(map.get(description[pBegin])!=null){
    setKeywordsArray(keywordsArray,map.get(description[pBegin]),1);
    }
    pBegin++;
    }
    if(pEnd>=nLen){
    break;
    }
    }
    for(int j=abstractBegin;j<=abstractEnd;j++){
    if(j!=abstractEnd){
    summary = summary+description[j]+" ";
    }else{
    summary +=description[j];
    }
    }
    return summary;
    }
    public Map<String,Integer> keywordsMap(String[] keywords){
    Map<String,Integer> map = new HashMap<String,Integer>();
    int len = keywords.length;
    for(int i=0;i<len;i++){
    map.put(keywords[i], i);
    }
    return map;
    }
    //设置关键字被访问到的次数
    public void setKeywordsArray(int[] keywordsArray,int i,int flag){ //flag:0 add flag:1 sub
    if(flag==0){
    keywordsArray[i]++;
    }else{
    keywordsArray[i]--;
    }
    }
    //检查是否包含全部关键字
    public boolean isAllExisted(){
    boolean result = true;
    for(int a:keywordsArray){
    if(a==0){
    result=false;
    break;
    }
    }
    return result;
    }

    public static void main(String[] args) {
    String description="hello software hello test world spring sun flower hello";
    String[] keywords = {"hello","world"};
    Abstract nAbstract = new Abstract(keywords);
    System.out.println(nAbstract.extractSummary(description, keywords));
    }
    }



     

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
    分享到: 更多
  • 相关阅读:
    WPF 绘图 和动画
    BZOJ 4028 分块
    操作系统与计算机网络
    go排序-基数排序
    go排序-睡眠排序
    go排序-堆排序
    go排序-构建大顶堆
    go排序 插入排序
    go排序-选择排序
    go排序-冒泡排序
  • 原文地址:https://www.cnblogs.com/flyoung2008/p/2437489.html
Copyright © 2011-2022 走看看