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

题意

在这里插入图片描述

解题思路

  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);
	}
}

猜你喜欢

转载自blog.csdn.net/m0_52744273/article/details/129737162