塔子哥喜欢字符-小米2023笔试(codefun2000)

题目链接
塔子哥喜欢字符-小米2023笔试(codefun2000)

题目内容

塔子哥天生偏爱一些字符,对于一个字符串,他总是想把字符串中的字符变成他偏爱的那些字符。如果字符串中某个字符不是他所偏爱的字符,称为非偏爱字符,那么他会将该非偏爱字符替换为字符串中距离该字符最近的一个偏爱的字符。
这里的距离定义即为字符在字符串中的对应下标之差的绝对值。如果有不止一个偏爱的字符距离非偏爱字符最近,那么塔子哥会选择最左边的那个偏爱字符来替换该非偏爱字符,这样就保证了替换后的字符串是唯一的。塔子哥的所有替换操作是同时进行的。
假定塔子哥有m个偏爱的字符,依次为c1 ,c2 ,…,cm ,当塔子哥看到一个长度为n的字符串s时,请你输出塔子哥在进行全部替换操作后形成的字符串。

输入描述

第一行输入两个正整数n,m。
接下来一行输入m个字符c1 ,c2 ,…,cm,每两个字符之间用空格隔开,表示塔子哥偏爱的字符。接下来一行输入一个字符串s。 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105 ,1≤m≤26,保证题目中所有的字符均为大写字符,塔子哥偏爱的字符互不相同,且偏爱字符至少出现一次。

输出描述

输出替换后的字符串

样例1

输入

5 3
A B C
DAZEC

输出

AAACC

题解1

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
int n, m, t, pos[N];
bool vis[N]; // 标记第i个字符是否是偏爱字符,vis[i]=1表示,第i个字符是偏爱字符
unordered_map<char,bool> hmap;
char c, s[N];

int main(){
	scanf("%d%d", &n, &m);
	getchar(); // 吃掉回车符
	for(int i = 1; i <= m; i++){
		if(i > 1) scanf("%c", &c);
		scanf("%c", &c);
		if(hmap.count(c) ==0) hmap[c] = 1; // 用来标记哪些字符是偏爱字符
	}
	scanf("%s", s + 1);
	for(int i = 1; s[i] != '\0'; i++){
		if(hmap.count(s[i])) pos[++t] = i, vis[i] = 1;
	}
	pos[t + 1] = pos[t];
	for(int i = 1; s[i] != '\0'; i++){
		if(!vis[i]){
			int left1 = 0, right1 = t+1, mid1;
			while(left1 + 1 < right1){ // 寻找在s[i]的左边离s[i]最近一个偏爱字符的位置 
				mid1 = (left1 + right1)/2;
				if(pos[mid1] < i) left1 = mid1;
				else right1 = mid1;
			}
			int left2 = 0, right2 = t+1, mid2;
			while(left2 + 1 < right2){ // 寻找在s[i]的右边离s[i]最近一个偏爱字符的位置 
				mid2 = (left2 + right2)/2;
				if(pos[mid2] > i) right2 = mid2;
				else left2 = mid2;
			}
			if(pos[left1] == 0) s[i] = s[pos[right2]]; // 在s[i]的左边没有找到偏爱字符
			else if(pos[right2] > n) s[i] = s[pos[left1]]; // 在s[i]的右边没有找到偏爱字符
			else {
				int a = i - pos[left1];
				int b = pos[right2] - i;
				if(a <= b) s[i] = s[pos[left1]]; // 在两个偏爱字符里面,选择距离近的一个
				else s[i] = s[pos[right2]];
			}
		}
	}
	printf("%s\n", s+1);
	return 0;
}
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值