3.5 最短摘要的声成

题目:

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

这题跟书上3.5差不多意思的题目。


思路解法:

  先来看看这些序列:

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的序列,并且找出其中的最小值,就可得到最终的结果。



代码:

#include <iostream>
#include <string>
#include <set>

using namespace std;

string context;
string query;
int targetBegin = 0;        //最后目标摘要的首指针
int targetEnd = 0;          //最后目标摘要的尾指针
int pBegin = 0, pEnd = 0;     //首尾循环指针

bool isAllExist(int &pBegin, int &pEnd) {
    set<char> s;
    for(int i = pBegin; i < pEnd; ++i) {
        s.insert(context[i]);
    }
    int length_of_query = query.length();
    for(int i = 0; i < length_of_query; ++i) {
        if(s.find(query[i]) == s.end()) return false;
    }
    return true;
}

int main() {
    cin >> context >> query;
    int n = context.length();
    int targetLength = n+1;       //最后目标摘要的总长度
    while(true) {
        while(!isAllExist(pBegin, pEnd) && pEnd < n) pEnd++;
        while(isAllExist(pBegin, pEnd)) {
            if(pEnd - pBegin < targetLength) {
                targetLength = pEnd - pBegin;
                targetBegin = pBegin;
                targetEnd = pEnd - 1;
            }
            pBegin++;
        }
        if(pEnd >= n) break;
    }
    for(int i = targetBegin; i <= targetEnd; ++i) cout << context[i];
    cout << endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值