蓝桥杯真题——人物相关性分析(二分解法)

文章介绍了一种使用Java解决编程竞赛中的字符串处理问题,具体是找出字符串中Alice和Bob相邻的情况。通过存储Alice和Bob的下标,利用二分搜索计算满足条件的配对数量,注意处理可能的数据范围溢出。文章还提到蓝桥杯官方OJ的测试数据可能存在错误,建议使用其他平台进行测试。
摘要由CSDN通过智能技术生成

题意

在这里插入图片描述

解题思路

  1. 先求出字符串中所有Alice的下标和Bob的下标,把前者的下标存到a数组中,后者存到b数组中。很显然,a数组和b数组都是非严格递增的。因为是java嘛,所以用List来代替数组。
  2. 遍历a数组,a数组的每个元素都代表一个Alice的下标,不妨把这个值称之为ax。那么对于这个alice,有哪些Bob是和它相邻的呢?很显然,是下标位于[ax - k - 3, ax + k + 5]之间的Bob。所以我们二分搜索一下b数组,获取b数组中处于[ax - k - 3, ax + k + 5]区间的值的个数,然后加到答案里就可以了。
  3. 最后的最后,答案的数值是有可能爆int的,所以要开long。太坑了,尤其是对于蓝桥杯这种不能实时测评并反馈的比赛。

ps:对于该题,蓝桥杯官方OJ的测试数据是错的,想测评代码请选择其他OJ,比如acwing等等。

代码

import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;

public class Main{
	static int k;
	static Scanner sc = new Scanner(System.in);
	static String s;
	// 从左到右,返回第一个大于等于x的数的下标,如果没有则返回-1
	static int lowerBound(int x, List<Integer> list) {
		if(list.get(list.size() - 1) < x) {
			return -1;
		}
		// 二分
		int l = 0, r = list.size() - 1;
		while(l < r) {
			int mid = (l + r) / 2;
			if(list.get(mid) >= x) {
				r = mid;
			}
			else {
				l = mid + 1;
			}
		}
		return l;
	}
	// 从右往左,返回第一个小于等于x的数的下标,如果没有返回-1
	static int findLastLower(int x, List<Integer> list) {
		if(list.get(list.size() - 1) <= x) {
			return list.size() - 1;
		}
		// 二分找到从左往右第一个大于x的数的下标
		int l = 0, r = list.size() - 1;
		while(l < r) {
			int mid = (l + r) / 2;
			if(list.get(mid) > x) {
				r = mid;
			}
			else {
				l = mid + 1;
			}
		}
		// l - 1就是从右往左第一个小于等于x的数的下标,当l等于0时,说明不存在,返回l - 1 即 -1
		return l - 1;
	}
	static boolean check(int i) {
		if(i < 0 || i >= s.length()) {
			return true;
		}
		if(s.charAt(i) <= 'z' && s.charAt(i) >= 'a') {
			return false;
		}
		if(s.charAt(i) <= 'Z' && s.charAt(i) >= 'A') {
			return false;
		}
		return true;
	}
	public static void main(String[] args) {
		k = sc.nextInt();
		s = sc.nextLine();
		s = sc.nextLine();
		long ans = 0;
		// a存放所有Alice的下标, b存放所有Bob的下标
		List<Integer> a = new ArrayList<>();
		List<Integer> b = new ArrayList<>();
		// 遍历字符串,填充a和b
		for(int i = 0; i < s.length(); i++) {
			if(i + 3 <= s.length() &&s.substring(i, i + 3).equals("Bob") && check(i + 3) && check(i - 1)) {
				b.add(i);
			}
			if(i + 5 <= s.length() && s.substring(i, i + 5).equals("Alice") && check(i + 5) && check(i - 1)) {
				a.add(i);
			}
		}
		for(int ax : a) {
			// ax为Alice下标,找到下标在[ax - k - 3, ax + k + 5]区间的bob个数,然后加到ans里面
			int l = lowerBound(ax - k - 3, b);
			int r = findLastLower(ax + k + 5, b);
			if(l == -1 || r == -1) {
				continue;
			}
			ans += r - l + 1;
		}
		System.out.println(ans);
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值