腾讯2021校园招聘-后台&综合-第一次笔试 8.23 20.00-22.00 Apare_xzc

腾讯2021校园招聘-后台&综合-第一次笔试

2020.8.23 20:00-22:00


2小时,5道编程题


第一题

        删除链表的第K个元素,输出删除后的链表。n个元素,n<=1E6, 1<=k<=n
送分题

#include 
using namespace std;
const int N = 1e6+100;
int a[N];
int main(void) {
	int n,x;
	cin>>n>>x;
	for(int i=1;i<=n;++i)
		scanf("%d",a+i);
	for(int i=1;i<=n;++i) {
		if(i==x) continue;
		printf("%d%c",a[i],i==n?'\n':' ');
	} 
	
	return 0;
} 

100%


第二题:

        长度不超过5000的字符串S,输出所有不相同的子串字典序第K小的。如aabb, k =3, a,aa,aab,aabb,ab,abb,b,bb, 答案为abb (1<=k<=5)

思路:

        一开始用map暴力存储所有子串,然后auto遍历得到第k个,内存超限,只过了40%,后来换成最大堆,每次只存1000个,不判重(觉得1000个重复的里面应该有前5个吧), 然后TLE,改成100个就WA,反正都是40%左右
        然后想到要不用字典树吧,所有的子串都插入到字典树中,然后线序遍历,得到第K个,不知道为什么只过了90%的数据

#include 
using namespace std;
char str[5000+100];
struct Trie{
	int son[2000000][26];
	int cnt,root;
	int getOne() {
		memset(son[cnt],-1,sizeof(son[cnt]));
		return cnt++;
	}
	void init() {
		cnt = 0;
		root = getOne();
	}
	void insert(char * s,int st,int ed) {
		int now = root;
		for(int i=st;i<=ed;++i) {
			int index = s[i]-'a';
			if(son[now][index]==-1) {
				son[now][index] = getOne();
			}
			now = son[now][index];
		}
	}
	void dfs(int& k,int now,string ss) {
		if(--k==0) {
			cout<<ss<<endl;
			exit(0);	
		}
		for(int i=0;i<26;++i) {
			if(son[now][i]!=-1) {
				dfs(k,son[now][i],ss+(char)('a'+i));
			}
		}
	}	
}tree;
int main(void) {
	int k;
	cin>>str>>k;
	++k;
	tree.init();
	int len = strlen(str);
	for(int i=0;i<len;++i) {
		tree.insert(str,i,len-1);
	}
	string sss;
	tree.dfs(k,tree.root,sss);
	return 0;
} 

90%


第三题

        把n拆成a+b(a,b>=0), 使得a,b的所有数位之和最大。n<=1E12,T组输出,T<=100

思路:贪心,拆成a = 999…9, b = n-a,然后直接计算

#include 
using namespace std;
int S(long long x) {
	int ans = 0;
	while(x>0) {
		ans += x%10;x/=10;
	}
	return ans;
} 
int main(void) {
	long long n;
	int T;
	cin>>T;
	while(T--) {
		scanf("%lld",&n);
		if(n<=9) {
			printf("%lld\n",n);continue;
		}
		long long x = 9;
		while(x*10+9<=n) {
			x = x*10+9;
		}
		n-=x;
		printf("%d\n",S(x)+S(n));
	} 
	return 0;
} 

100%


第四题

        n个模板并排放置,宽度都为1,长度为hi, (n<=5000, hi<=1E9),每次可以横着刷或者竖着刷,刷一次不能有断层

Sample Input1
5
2 2 1 2 1
Sample Output1
3
Sample Input2
2 2
Sample Output2
2

暂时没什么好的思路,如果都是竖着刷,那么要刷n次,所以答案一定<=n, 直接输出n可以对55%…
是dp吗?


第五题

        给一个长度不超过400的字符串,1E5个询问 ,每次询问一个区间的子串最少可以切分分成几个回文子串

ababa 4
1 4
1 5
2 5
1 3

2
1
2
1

思路:

先dp处理出所有区间是否是回文子串,然后处理出以每个位置为起点,可以为回文子串的终点,存到vector数组中。然后贪心匹配。
只通过了20%…

#include 
using namespace std;
char s[500+10]; 
vector<int> v[510];
int dp[510][510];//每个区间是否回文 
int main(void) {
	int Q,L,R,len;
	scanf("%s",s+1);
	scanf("%d",&Q);
	len = strlen(s+1);
	for(int i=1;i<=len;++i) 
		v[i].push_back(i),dp[i][i]=1;
	for(int i=1;i<len;++i) {
		if(s[i]==s[i+1]) dp[i][i+1] = 1,v[i].push_back(i+1);
	}
	for(int lenth=3;lenth<=len;++lenth) {
		for(int left=1;left+lenth-1<=len;++left) {
			int right = left+lenth-1;
			if(s[left]==s[right]&&dp[left+1][right-1] == 1) 
				dp[left][right]=1, v[left].push_back(right);
		}
	}
	while(Q--) {
		scanf("%d%d",&L,&R);
		int ans = 0;
		int x = L;
		while(1) {
			int id = upper_bound(v[x].begin(),v[x].end(),R)-v[x].begin()-1;
			x = v[x][id]+1;
			++ans;
			if(x==R+1) break;
		}
		printf("%d\n",ans);
	}
	return 0;
} 

2020.8.23 23:37
xzc


你可能感兴趣的:(腾讯2021校园招聘-后台&综合-第一次笔试 8.23 20.00-22.00 Apare_xzc)