尺取法之最短摘要的总结

1. 学会了使用JDK中的Arrays.binarySearch();来查找当前元素是否在数组里面,假如元素存在那么方法返回元素在数组中的下标,假如不存在则返回-1,这个方法对于处理字符串的问题的时候有时候可能很有效

2. 学会了如何处理关键字中有重复的问题

① 原来解决这个问题是使用辅助数组的方法,首先声明一个与要查找的关键字相同长度的数组来记录查找到的关键字,使用一个for循环来扫描单词,假如发现一个关键字那么在辅助数组上记录上1,假如关键字有重复的话那么还需要声明另外一个辅助的数组来处理该关键字是否被访问过,假如没有第二个辅助数组那么扫描到重复的关键字的时候会丢弃掉扫描到重复的关键字而恰好关键字中有重复的时候那么这样就会出现问题,所以使用两个辅助数组可以解决关键字存在重复的问题用来标记是否被访问过

import java.util.Arrays;
public class Main{
	//有重复的关键字的话我是使用另外一个数组来标记该元素是否被访问过
	public static void main(String[] args) {
		solve(new String[]{"a","b","a","a","b","c","d","h","e","f","f","c","c","d","e","f","d","h","q"},
		//new String[]{"c","c","q"});
		new String[]{"a","a","c"});
	}

	private static void solve(String[] words, String[] keys) {
		int keyFound[] = new int[keys.length];
		int keyRecord[] = new int[keys.length];
		int index = 0;
		int p = -1;
		int len = Integer.MAX_VALUE;
		int begin = -1;
		int end = -1;
		for(int i = 0;i<words.length;i++){
			Arrays.fill(keyFound, 0);
			Arrays.fill(keyRecord, 0);
			index = check(words[i],keys,keyRecord);
			if(index==-1||keyRecord[index]==1||keyFound[index]==1){
				continue;
			}
			
			int j;
			if(p==-1){
				j = i+1;
			}else{
				j = p;
			}
			//判断上一次的找到的子串中是否有更短的子串
			if(j-i+1>=keyFound.length&&end!=-1){
				for(int k = i;k<=j;k++){
					System.out.println("k = "+k);
					index = check(words[k],keys,keyRecord);
					//System.out.println("index = "+index);
					if(index!=-1&&keyRecord[index]!=1&&keyFound[index]!=1){
						keyFound[index] = 1;
						keyRecord[index] = 1;
					}
					if(sum(keyFound)==keyFound.length){
						if(j-i+1<len){
							len = j-i+1;
							begin = i;
							end = j;
							p = j;
						}
						break;
					}
				}
				continue;
			}
			
			for(;j<words.length;j++){
				index = check(words[j],keys,keyRecord);
				if(index!=-1&&keyRecord[index]!=1&&keyFound[index]!=1){
					keyFound[index] = 1;
					keyRecord[index] = 1;
				}
				if(sum(keyFound)==keyFound.length){
					if(j-i+1<len){
						len = j-i+1;
						begin = i;
						end = j;
						p = j;
					}
					break;
				}
			}
		}	
			print(begin,end,words);
	}

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

	private static int sum(int[] keyFound) {
		int sum = 0;
		for(int i = 0;i<keyFound.length;i++){
			sum+=keyFound[i];
		}
		return sum;
	}

	private static int check(String string, String[] keys,int keyRecord[]) {
		for(int i = 0;i<keys.length;i++){
			if(string.equals(keys[i])&&keyRecord[i]!=1){
				//keyRecord[i] = 1;
				return i;
			}
		}
		return -1;
	}
}

② 把关键字放入到map中可以很好解决这个问题而且不用辅助数组来解决

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Main{
	public static void main(String[] args) {
		//当关键字有重复的时候把关键字放入到map中可以很方便的处理关键字重复带来的问题
		solve(new String[]{"a","ab","a","a","b","c","d","h","e","f","f","c","c","d","e","f","d","h","q"},
		new String[]{"a","e"});	
	}

	private static void solve(String[] words, String[] keys) {
		int len = Integer.MAX_VALUE;
		int begin = 0;
		int end = -1;
		int j = 0;
		for(int i = 0;i<words.length;i++){
			//使用二分查找来查找数组中是否含有某个关键字的下标,假如当前下标所在的单词不是关键字直接返回-1
			int index = Arrays.binarySearch(keys, words[i]);
			if(index==-1){
				continue;
			}
			
			//i可能找到一个关键字但是最后没有找到符合的所以j到最后可能到达了words的长度所以需要加上j<words.length这个条件才不会越界
			if(j-i+1>=keys.length&&j<words.length&&containAll(words, keys, i, j)){
				if(j-i+1<len){
					len = j-i+1;
					begin = i;
					end = j;
				}
				//继续寻找,因为有可能上一个串中嵌套着更小的串
				continue;
			}
			if(j==0){
				j = i + 1;
			}
			//尺取法搜寻囊括关键字的的下标
			for(;j<words.length;j++){
				index = Arrays.binarySearch(keys, words[j]);
				if(index==-1){
					continue;
				}else{
					if(containAll(words,keys,i,j)){
						if(j-i+1<len){
							len = j-i+1;
							begin = i;
							end = j;
						}
						break;
					}
				}
			}	
		}	
		print(words,begin,end);
	}

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

	private static boolean containAll(String[] words, String[] keys, int i, int j) {
		//把单词放入map中可以很好的处理关键字重复的问题
		Map<String,Integer> map1 = new HashMap<String,Integer>();
		for(int k = 0;k<keys.length;k++){
			String key =keys[k];
			if(map1.get(key)==null){
				map1.put(key, 1);
			}else{
				//关键字重复,例如关键字b有两个那么当map.getKey("bb")==2
				map1.put(key,map1.get(key)+1);
			}
		}
		Map<String,Integer> map2 = new HashMap<String,Integer>();
		for(int k = i;k<=j;k++){
			String key = words[k];
			if(map2.get(key)==null){
				map2.put(key, 1);
			}else{
				//关键字重复
				map2.put(key,map2.get(key)+1);
			}
		}
		
		//遍历关键字判断i到j中的所有单词是否囊括在内
		for(Map.Entry<String, Integer> e:map1.entrySet()){
			if(map2.get(e.getKey())==null||map2.get(e.getKey())<e.getValue()){
				return false;
			}
		}
		return true;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值