Java 生成最短摘要 尺取法

Posted 覃会程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 生成最短摘要 尺取法相关的知识,希望对你有一定的参考价值。

最短摘要,这是《编程之美》里的一个问题:

简单点说就是你在搜索引擎上输入关键字,然后后找出包含你输入的所有关键字最短的一段话(或者说是一串字符串)。

下面是阿里巴巴2011年的一个笔试题,也是关于最短摘要的问题。

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

解法思路:
这题可以用暴力法破解,以每一个单词作为起点,开始向后扫描,当包含N个关键字时就与之前得到的最短字符串进行比较,如果更短就替换。否则开始下一个起点的扫描。但是这个方法时间复杂度很高为:MMN

这题用尺取法的话可以提高效率,尺取法通常是指保留数组的一对下标(起点和终点),然后根据实际情况交替推进两个端点直到得出答案。这种操作很像尺取虫的爬行方式,故而得名。
结合本题的实际情况就是:从第一个单词开始扫描,直到碰到关键字就记录它的下标作为起点,然后终点下标接着向后扫描直到起点和终点之间的字符串包含了所有关键字,记录下起点和终点,然后起点向后移动终点不变,如果还是包含所有关键字就记录起点和终点下标;直到不能包含所有关键字时起点不动终点向后移。又直到包含所有关键字时终点停下记录起点和终点的下标。如此一直循环到字符串结束。从所有记录中找到最短的记录(也可以在记录的时候进行比较,如果更短就进行更新记录,这样可以省空间)。

代码如下:


import java.util.Arrays;

public class 生成最短摘要 
	public static void main(String[] args)
		String[] w = "a","b","c","d","e","s","d","a","t";
		String[] keys ="a","b","c";
		solve(w,keys);
	
	
	//返回word在q数组中的下标序号,不存在就返回-1
	static int indexOf(String[] q, String word)
		for(int i=0; i<q.length; i++)
			if(q[i].equals(word))
				return i;
		
		return -1;
	
	
	static void solve(String[] w, String[] keys)
		int begin = -1;  
		int end = -1;
		int p2 = -1;  //上一次囊括所有关键字的右边界
		//定义最小长度,初始化为int的最大值2的31次方减一
		int minlen = Integer.MAX_VALUE;
		//定义关键字数组,辅助判断是否包含所有关键字
		int[] keyfoud = new int[keys.length];
		for(int i=0; i<w.length; i++)
			//将数组清零,进行新的一段字符串统计
			Arrays.fill(keyfoud, 0);
			String word = w[i];
			int index = indexOf(keys, word);
			if(-1==index)//不是关键字继续先前移动
				continue;
			else
				keyfoud[index] = 1;//进行标记
			
			
			int j;
			//如果不是第一次循环j等于上一次囊括所有关键字的右边界
			if(p2!=-1)
				j = p2;
			else
				j = i+1;
			for(; j<w.length; j++)
				String word2 = w[j];
				int index2 = indexOf(keys,word2);
				if(index2==-1 || keyfoud[index2]==1)
					//不是关键字或者已经标记过了就继续向后移动
					continue;
				else
					keyfoud[index2] = 1;//标记一下
				
				if(sum(keyfoud)==keyfoud.length)
					//关键字齐了
					p2 = j;
					if(j-i+1 < minlen)//更新
						begin = i;
						end = j;
						minlen = end - begin +1;
					
					break;
				
			
		
		//打印最短摘要
		print(w,begin,end);
	

	private static void print(String[] w, int begin, int end) 
		for(int i=begin; i<=end; i++)
			System.out.print(w[i] + " ");
		
	

	//数组求和函数
	private static int sum(int[] keyfoud) 
		int sum = 0;
		for(int i=0; i<keyfoud.length; i++)
			sum += keyfoud[i];
		
		return sum;
	


备注:这个代码是不考虑关键字间会出现重复的情况,如果关键字之间有重复的情况需要进行去重。

关键字重复的情况请看这篇文章:
hiho字符串 (尺取法的应用)

以上是关于Java 生成最短摘要 尺取法的主要内容,如果未能解决你的问题,请参考以下文章

字符串----hiho字符串(尺取法)

牛客小白月赛34 F dd爱框框 (尺取法)

51nod 1127 最短的包含字符串(尺取法)

尺取法

[51NOD1127]最短的包含字符串(尺取法)

尺取法