人物相关性分析 2019年
【问题描述】 小明正在分析一本小说中的人物相关性。 他想知道在小说中 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 个字符。 注意 :
-
Alice 和 Bob 是大小写敏感的, alice 或 bob 等并不计算在内。
-
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 。
运用差分和前缀和进行求解:
如果有标点符号多种,记得稍微修改一下判断条件。此处标点以:" " , . 若有?!等自行修改if条件
import java.util.ArrayList;
import java.util.Scanner;
/**
* @version v-1.8.0_131.
* @auther Jack hou Email:256595662@qq.com
* @data 2021/3/28/16:42
* @Description:人物相关性2019,差分,前缀和。
**/
public class 人物相关性2019 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int k=scanner.nextInt();
scanner.nextLine();
String s=scanner.nextLine();
char[] c=s.toCharArray();//可以不给定确定的char[]数组大小,直接用toCharArray()给char[]数组赋值
ArrayList<Integer> Al=new ArrayList<Integer>();//储存Alice出现的位置的下标
ArrayList<Integer> Bo=new ArrayList<Integer>();
for (int i = 0; i <c.length ; i++) {
if ((i-1<0||c[i-1]=='.'||c[i-1]==' ')&&c[i]=='A'&&c[i+1]=='l'&&c[i+2]=='i'&&c[i+3]=='c'&&c[i+4]=='e'&&(c[i+5]=='.'||c[i+5]==' ')){
//i-1<0||c[i-1]=='.'||c[i-1]==' '当i为第一项,或Alice前面没有字母且后面也没有字母,则Alice才为有效的独立Alice
Al.add(i);//将Alice出现的i位置加入到ArrayList中
}
}
for (int i = 0; i <c.length ; i++) {
if ((i-1<0||c[i-1]=='.'||c[i-1]==' ')&&c[i]=='B'&&c[i+1]=='o'&&c[i+2]=='b'&&(c[i+3]=='.'&&c[i+3]=='.')){
Bo.add(i);
}
}
long ans=0;
int CF[]=new int[1000006];//差分数组
int QZH[]=new int[1000006];//前缀和数组
for(int t:Al) {
CF[Math.max(0,t-k-3)]++;//差分操作:对区间端点进行左端点++,区间右端点--,可以使得此区间内原本元素都加一,不是差分都加一,只有端点进行操作,左端点差分为:1,右端点为-1,中间差分元素都为0.
CF[Math.min(1000000, t+k+5)]--;
}
QZH[0]=CF[0];
for (int i = 1; i < 1000006; i++) {
QZH[i]=QZH[i-1]+CF[i];//进行前缀和计算,由于这里前缀和元素原本都为0,所以加一后为1,在区间重叠部分加两次会变成2
}
for(int t:Bo) {
ans+=QZH[t];//有多少个Bob,就有多少个相关性答案,既包含了区间不重叠的普通情况1,也包含了区间重叠产生的2.
}
System.out.println(ans);
}
}
原创不易,点点赞吧。