字节跳动2018校招算法方向(第二批)

算法题集:https://blog.csdn.net/weixin_39778570/article/details/83187443

第一题

[编程题]用户喜好
时间限制:C/C++ 3秒,其他语言6秒

空间限制:C/C++ 256M,其他语言512M

为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为k。因为一些特殊的原因,不会出现一个查询的用户区间完全覆盖另一个查询的用户区间(不存在L1<=L2<=R2<=R1)。



输入描述:
输入: 第1行为n代表用户的个数 第2行为n个整数,第i个代表用户标号为i的用户对某类文章的喜好度 第3行为一个正整数q代表查询的组数  第4行到第(3+q)行,每行包含3个整数l,r,k代表一组查询,即标号为l<=i<=r的用户中对这类文章喜好值为k的用户的个数。 数据范围n <= 300000,q<=300000 k是整型

输出描述:
输出:一共q行,每行一个整数代表喜好值为k的用户的个数

输入例子1:
5
1 2 3 3 5
3
1 2 1
2 4 5
3 5 3

输出例子1:
1
0
2

例子说明1:
样例解释:
有5个用户,喜好值为分别为1、2、3、3、5,
第一组询问对于标号[1,2]的用户喜好值为1的用户的个数是1
第二组询问对于标号[2,4]的用户喜好值为5的用户的个数是0
第三组询问对于标号[3,5]的用户喜好值为3的用户的个数是2

莫队裸题
离线区间统计问题可以考虑使用莫队来维护

#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N = 3e5+5;
int n,m,block,a[N],ans[N],ANS[N];
struct query{
	int l, r, k, id;
}q[N];
bool cmp(const query &a, const query &b){
	return (a.r/block) == (a.r/block) ? a.l<b.l : a.r<b.r;
} 
void del(int x){
	ANS[a[x]]--;
}
void add(int x){
	ANS[a[x]]++;
}
int main(){
	scanf("%d",&n);	
	fo(i,1,n)scanf("%d",&a[i]);
	scanf("%d",&m);
	fo(i,1,m){
		scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
		q[i].id = i;
	}
	
	block = n/sqrt(m);
	sort(q+1,q+1+m,cmp);
	int l=1,r=0;
	fo(i,1,m){
		int ql=q[i].l,qr=q[i].r,qk=q[i].k,qid=q[i].id;
		while(r>qr)del(r--);
		while(l<ql)del(l++);
		while(r<qr)add(++r);
		while(l>ql)add(--l);
		ans[qid] = ANS[qk];
	}
	fo(i,1,m){
		printf("%d\n",ans[i]);
	}
	return 0;
} 

第二题

链接:https://www.nowcoder.com/questionTerminal/8da0ea4b4853464795f5c32634a1b06f
来源:牛客网

[编程题]字母交换
热度指数:1995时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 32M,其他语言64M
算法知识视频讲解
【编码题】字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?



输入描述:
第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)


输出描述:
一个非负整数,表示操作之后,连续最长的相同字母数量。
示例1
输入
abcbaa 2
输出
2
说明
使2个字母a连续出现,至少需要3次操作。即把第1个位置上的a移动到第4个位置。
所以在至多操作2次的情况下,最多只能使2个b或2个a连续出现。

直接暴力模拟每个环就好啦

#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=1e4+5;
int n,m,c; 
vector<int> color[N];	
bool ok[55];
int num[55];
int main(){
	scanf("%d%d%d",&n,&m,&c);
	fo(i,1,n){
		int t;scanf("%d",&t);	
		while(t--){
			int x;scanf("%d",&x);
			color[i].push_back(x);  
		}
	}
	fo(i,1,m){
		for(int j=0; j<color[i].size(); j++){
			if(++num[color[i][j]]>=2){
				ok[color[i][j]]=1;
			}	
		}
	}
	fo(i,2,n){
		int l = i-1;
		int r = (i+m-2)%n + 1;
		for(int j=0; j<color[l].size(); j++){
			num[color[l][j]]--;	
		}
		for(int j=0; j<color[r].size(); j++){
			if(++num[color[r][j]]>=2){
				ok[color[r][j]]=1;
			}	
		}
	} 
	int ans = 0;
	fo(i,1,c){
		if(ok[i])ans++;
	}
	printf("%d\n",ans);
	return 0;
} 

第三题

程题]字母交换
时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 32M,其他语言64M

【编码题】字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?



输入描述:
第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)

输出描述:
一个非负整数,表示操作之后,连续最长的相同字母数量。

输入例子1:
abcbaa 2

输出例子1:
2

例子说明1:
使2个字母a连续出现,至少需要3次操作。即把第1个位置上的a移动到第4个位置。
所以在至多操作2次的情况下,最多只能使2个b或2个a连续出现。

类似区间DP问题…我居然没做出来,我太菜了
dp[i][j] 标识第i个到第j个相同字母移动在一起的最少交换次数
v[i]表示第i个字母位置
dp[i][j] = dp[i+1][j-1]+(v[j]-v[i]-1) - (j-i-1);

#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=1005;
//char s[N];
int m, ans;
vector<int> c[27];
int dp[N][N]; 
string s;
// dp[i][j] 标识第i个到第j个移动在一起的最少交换次数 
// dp[i][j] = dp[i+1][j-1] + (c[字母][j]-c[字母][i]-1) - (j-i-1) 
void calc(const vector<int> & v){
	int n = v.size();
	memset(dp,0,sizeof(dp));
	for(int i=0; i+1<n; i++){
		dp[i][i+1] = v[i+1]-v[i]-1; 
	}
	// 区间dp思想, 距离,起点,断点(这里没有) 
	for(int r=2; r<n; r++){
		for(int i=0; i+r<n; i++){
			int j=i+r;
			dp[i][j] = dp[i+1][j-1]+(v[j]-v[i]-1) - (j-i-1);
		}
	} 
	for(int i=0; i<n; ++i){
		for(int j=i+1; j<n; ++j){
			if(dp[i][j]<=m){
				ans = max(ans, j-i+1);
			}
		}
	}	 
}
void solve(){
	int len = s.length();
	// 每个字母 
	fo(i,0,len-1){
		c[s[i]-'a'].push_back(i);
	} 
	if(len>=1)ans=1;
	fo(i,0,25){
		calc(c[i]);
	}
	printf("%d\n", ans); 
} 
int main(){
//	scanf("%s %d", s+1, &m); 
	cin >> s >> m;
	solve();
	
	return 0;
} 

你可能感兴趣的:(ACM算法日常)