蓝桥杯2019年真题:人物相关性分析

题目

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分

【问题描述】 
小明正在分析一本小说中的人物相关性。他想知道在小说中 Alice 和 Bob 有多少次同时出现。 
更准确的说,小明定义 Alice 和 Bob“同时出现”的意思是:
在小说文本 中 Alice 和 Bob 之间不超过 K 个字符。 
例如以下文本: 
This is a story about Alice and Bob. Alice wants to send a private message to Bob. 
假设 K = 20,则 Alice 和 Bob 同时出现了 2 次,
分别是”Alice and Bob” 和”Bob. Alice”。
前者 Alice 和 Bob 之间有 5 个字符,后者有 2 个字符。 
注意: 
1.Alice 和 Bob 是大小写敏感的,alice 或 bob 等并不计算在内。 
2.Alice 和 Bob 应为单独的单词,前后可以有标点符号和空格,但是不能 有字母。
例如 Bobbi 並不算出现了 Bob。

【输入格式】
第一行包含一个整数 K。 第二行包含一行字符串,只包含大小写字母、标点符号和空格。
长度不超 过 1000000。

【输出格式】 
输出一个整数,表示 Alice 和 Bob 同时出现的次数。

【样例输入】 
20
This is a story about Alice and Bob. Alice wants to send a private message to Bob.

【样例输出】 
2
【评测用例规模与约定】 
对于所有评测用例,1≤ K ≤1000000

答案

package competition3;

import java.util.Scanner;

public class RelevanceOfMy2
{
    
    
	//因为结果可以实在太大,所以计算结果的必须定义比int更大的类型才可以得满分
	public static long result=0;
	public static int K;
	public static String text;
	public static int length;
	
	public static void main(String[] args)
	{
    
    
		Scanner in =new Scanner(System.in);
		K=in.nextInt();
		in.nextLine();
		text=in.nextLine();
		length=text.length();
		
		//保存所有Alice的位置
		int[] number1=new int[1000000];
		int[] number2=new int[1000000];
		int count1=0,count2=0;
		
		in.close();
		for(int x=0;x<length;x++)
		{
    
    
			//必须保证前面的不是字母,后面的不是字母
			if(!IsLetter(x-1) && x+4<length && !IsLetter(x+5) && text.substring(x, x+5).equals("Alice") )
			{
    
    
				number1[count1++]=x;
			}
			if(!IsLetter(x-1) && x+2<length && !IsLetter(x+3) && text.substring(x, x+3).equals("Bob") )
			{
    
    
				number2[count2++]=x;
			}
		}
		
		if(count1==0 || count2==0)
		{
    
    
			result=0;
		}
		/*
		 * 因为我们上面找出来的Alice和Bob的位置都是升序的,所以我们可以
		 * 遍历每一个Alice,每一个Alice都有一个区间是所有的Bob都是可以组合的
		 * 那么我们就使用right和left来表示这个区间,然后遍历每一个Alice的时候
		 * 区间也会随着移动改变,这样算法复杂度接近线性,所以能通过的
		 */
		else
		{
    
    
			int left=0,right=-1;
			for(int x=0;x<count1;x++)
			{
    
    
				while(right+1<count2 && number2[right+1]<=number1[x]+K+5)
				{
    
    
					right++;
				}
				while(number2[left]+3+K<number1[x])
				{
    
    
					left++;
				}
				result += right-left+1;
			}
		}
		System.out.println(result);
	}
	public static boolean IsLetter(int index)
	{
    
    
		if(index<0 || index >=length)
			return false;
		char charAt = text.charAt(index);
		return (charAt>='a' && charAt<='z')||(charAt>='A' && charAt<='Z');			
	}
}

package competition3;

import java.util.Scanner;

public class RelevanceOfMy3
{
    
    
	//因为结果可以实在太大,所以计算结果的必须定义比int更大的类型才可以得满分
	public static long result=0;
	public static int K;
	public static String text;
	public static int length;
	//保存所有Alice的位置
	public static int[] number1=new int[1000000];
	public static int[] number2=new int[1000000];
	
	public static int count1=0,count2=0;
	
	public static void main(String[] args)
	{
    
    
		Scanner in =new Scanner(System.in);
		K=in.nextInt();
		in.nextLine();
		text=in.nextLine();
		length=text.length();
		
		in.close();
		for(int x=0;x<length;x++)
		{
    
    
			//必须保证前面的不是字母,后面的不是字母
			if(!IsLetter(x-1) && x+4<length && !IsLetter(x+5) && text.substring(x, x+5).equals("Alice") )
			{
    
    
				number1[count1++]=x;
			}
			if(!IsLetter(x-1) && x+2<length && !IsLetter(x+3) && text.substring(x, x+3).equals("Bob") )
			{
    
    
				number2[count2++]=x;
			}
		}
		
		if(count1==0 || count2==0)
		{
    
    
			result=0;
		}
		else
		{
    
    
			for(int x=0;x<count1;x++)
			{
    
    
				int left = FindLeft(number1[x]-K-3);
				if(number2[left]>number1[x]+K+5)
				{
    
    
					continue;
				}
				int right=FindRight(number1[x]+K+5);
				result +=right-left+1;					
			}
		}
		System.out.println(result);
	}
	public static int FindLeft(int index)
	{
    
    
		int left=0,right=count2-1;
		int middle;
		while(left<right)
		{
    
    
			middle=left+right>>1;
			if(index<=number2[middle])
			{
    
    
				right=middle;
			}
			else
			{
    
    
				left=middle+1;
			}
//			if(index>=number1[middle])
//			{
    
    
//				left=middle;
//			}
//			else
//			{
    
    
//				right=middle-1;
//			}
		}
		return left;
	}
	public static int FindRight(int index)
	{
    
    
		int left=0,right=count2-1;
		int middle;
		while(left<right)
		{
    
    
			middle=left+right +1>>1;
			if(index>=number2[middle])
			{
    
    
				left=middle;
			}
			else
			{
    
    
				right=middle-1;
			}
//			if(index <=number2[middle])
//			{
    
    
//				right=middle;
//			}
//			else
//			{
    
    
//				left=middle+1;
//			}
		}
		return right;
	}
	public static boolean IsLetter(int index)
	{
    
    
		if(index<0 || index >=length)
			return false;
		char charAt = text.charAt(index);
		return (charAt>='a' && charAt<='z')||(charAt>='A' && charAt<='Z');			
	}
}

对应的二分查找比它小的最大值和比它大的最小值

package competition3;

public class BinarySearch
{
    
    
	public static int[] arr={
    
    1,3,5,8,9,12,14,18,19};
	public static void main(String[] args)
	{
    
    
		/*
		 * 现在是给定一个有序的数组,你需要使用二分查找,
		 * 给你一个数组存在的数number,查到比小的最大值
		 * 还有比number大的最小值
		 */
		System.out.println(BinarySearchSmall(0));
		System.out.println(BinarySearchBig(15));
	}
	public static int BinarySearchSmall(int number)
	{
    
    
		/*
		 * 这里是找比它小的最大值,
		 * 如果目标值比中间值小于或者等于,就将右边的边界缩成中间的
		 * 如果目标值比中间值大,就将左边缩成middle+1
		 */
		int x=0,y=arr.length-1;
		while(x<y)
		{
    
    
			int middle=x+y>>1;
			if(number <= arr[middle])
			{
    
    
				y=middle;
			}
			else
			{
    
    
				x=middle+1;
			}
			/*
			 * 这里只能像上面那样写,不能像下面这样写,下面写会出错的
			 * 比如下面的:如果是1,3,然后number是2
			 * 那么就会进入死循环,一直x=middle
			 * 而上面的先处理number<=arr[middle]就不会出现问题,
			 * 因为middle不可能和中间值相同的的,以不可能进入死循环
			 */
//			if(number>=arr[middle])
//			{
    
    
//				x=middle;
//			}
//			else
//			{
    
    
//				y=middle-1;
//			}
		}
		return x;
	}
	public static int BinarySearchBig(int number)
	{
    
    
		int x=0,y=arr.length-1;
		while(x<y)
		{
    
    
			/*
			 * 这里为什么要加多一个1呢?
			 * 就是像上面所说的,不让它进入死循环,
			 * 因为如果不加1的话,会出现x=middle的情况
			 * 还有你可能发现了,寻找比它小或者比它大的这两个问题
			 * 找比它小的最大值就得先处理目标值比中间值小的情况先
			 * 找比它大的最小值就得先处理目标值比中间值大的情况先
			 */
			int middle=x+y+1>>1;
			if(number >= arr[middle])
			{
    
    
				x=middle;
			}
			else
			{
    
    
				y=middle-1;
			}
//			if(number <= arr[middle])
//			{
    
    
//				y=middle;
//			}
//			else
//			{
    
    
//				x=middle+1;
//			}
		}
		return x;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_43416157/article/details/108922962