今日头条2018校招编程题思路

第一题,串珠

颜色用二进制存储。枚举颜色后twp-point/滑动窗口解决。 每次往右边加进来一个点判断该点是否存在目前枚举的颜色,存在cnt++; 弹出最左边的点,如果最左边的点存在目前枚举的颜色,cnt--。如果cnt>1. ans++。
复杂度O(n)

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<time.h>
#include<cmath>
#include<sstream>
#include<assert.h>
using namespace std;
typedef long long int LL;
const LL INF = 0x7FFFFFFFFFFFFFFF;
const int inf = 0x3f3f3f3f;
const int MAXN = 10000 + 1024;
LL col[MAXN * 2];

int main(){
	int n, m, c;
	while (~scanf("%d%d%d", &n, &m, &c)){
		memset(col, 0, sizeof(col));
		for (int i = 1; i <= n; i++){
			int Size, val;
			scanf("%d", &Size);
			for (int j = 1; j <= Size; j++){
				scanf("%d", &val);
				col[i] |= (1LL << val);
			}
			col[i + n] = col[i];
		}
		if (m > n){ printf("0\n"); }
		else{
			int ans = 0;
			for (int k = 1; k <= c; k++){
				int cnt = 0; bool flag = false;
				for (int i = 1; i <= m; i++){
					if (col[i] & (1LL << k)){ cnt++; }
				}
				if (cnt > 1){ flag = true; }
				for (int i = m + 1; i <= n * 2 && i - m <= n && !flag; i++){
					if (col[i - m] & (1LL << k)){ cnt--; }
					if (col[i] & (1LL << k)){ cnt++; }
					if (cnt > 1){ flag = true; }
				}
				if (flag){ ans++; }
			}
			printf("%d\n", ans);
		}
	}
	return 0;
}

第二题, 区间内k值的多少
离线处理,把询问全部读入,分块排序询问,用map来维护某个值出现的次数,莫队转移。
复杂度O(q*sqrt(n)*log(n))
另外一种方式是离散化k,然后对于每个k用一个vector保存值为k的人的下标。对于询问我们可以定位到vector[k]这个数组,然后用二分查找看有多少个人在[l,r]之间。
复杂度O(n*log(n)+q*log(n))
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<map>
#include<vector>
#include<cmath>
using namespace std;
typedef long long int LL;
const int MAXN = 300000+1024;
int be[MAXN], ans[MAXN];
LL a[MAXN];
map<LL, int> mp;
struct Qry{
	int l, r, id;
	LL k;
	bool operator<(const Qry &o)const{
		if (be[l] == be[o.l]) return (be[l] & 1) ? r > o.r:r < o.r;
		return l < o.l;
	}
}Q[MAXN];
void add(LL x){
	mp[x]++;
}
void del(LL x){
	mp[x]--;
}
int main(){
#ifdef kirito
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	int n, q;
	while (~scanf("%d", &n)){
		int S = (int)sqrt(n + 0.5);
		for (int i = 0; i <= n; ++i) be[i] = i / S;
		for (int i = 1; i <= n; ++i) scanf("%lld",&a[i]);
		scanf("%d", &q);
		for (int i = 0; i < q; ++i){
			scanf("%d%d%lld", &Q[i].l, &Q[i].r, &Q[i].k);
			Q[i].id = i;
		}
		sort(Q, Q + q);
		for (int i = 0, l = 1, r = 0; i < q; ++i){
			while (r < Q[i].r) add(a[++r]);
			while (l > Q[i].l) add(a[--l]);
			while (l < Q[i].l) del(a[l++]);
			while (r > Q[i].r) del(a[r--]);
			ans[Q[i].id] = mp[Q[i].k];
		}
		for (int i = 0; i < q; ++i){
			printf("%d\n", ans[i]);
		}
	}
	return 0;
} 

第三题,字符串相邻字符交换有限次数,得到最长的连续相同字符长度
枚举每种字母,计算该字母在字符串中出现的位置。再枚举以该字符每个位置为中心点,两边的字符往这个中心靠拢,计算一个距离的前缀和, 再枚举左端点,二分找右端点。
复杂度O(26*|s|*|s|*log(|s|))
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<time.h>
#include<cmath>
#include<sstream>
#include<assert.h>
using namespace std;
typedef long long int LL;
const LL INF = 0x7FFFFFFFFFFFFFFF;
const int inf = 0x3f3f3f3f;
const int MAXN = 10000 + 1024;
char str[MAXN];
vector<int>pos;
int dst[MAXN],preSum[MAXN];
int main(){
#ifdef kirito
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	int m;
	while (~scanf("%s%d", str, &m)){
		int len = strlen(str);
		int ans = 0;
		for (int i = 0; i < 26; i++){
			pos.clear();
			for (int j = 0; j < len; j++){
				if (str[j] == ('a' + i)){
					pos.push_back(j);
				}
			}
			int Size = pos.size();
			for (int j = 0; j < Size; j++){
				memset(dst, 0, sizeof(dst));
				memset(preSum, 0, sizeof(preSum));
				for (int _j = 0; _j < Size; _j++){
					dst[_j] = abs(pos[_j] - pos[j]);
				}
				for (int _j = j + 1; _j < Size; _j++){
					preSum[_j] = preSum[_j - 1] + dst[_j] - (_j - j);
				}
				for (int _j = j - 1; _j >= 0; _j--){
					preSum[_j] = preSum[_j + 1] + dst[_j] - (j - _j);
				}
				preSum[Size] = inf;
				for (int _j = j; _j >= 0; _j--){
					int need = m - preSum[_j];
					if (j + 1 >= Size){ continue; }
					int pos = upper_bound(preSum + j + 1, preSum + Size,need) - preSum;
					pos--;
					if (pos >= j + 1 && pos < Size){
						ans = max(ans, pos - j + 1 + (j - _j));
					}
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

#字节跳动#
全部评论
第三题思路很棒,我完全没想法
点赞 回复 分享
发布于 2017-09-11 17:26
第三题,我的算法复杂度 O(26*n*log(n))
点赞 回复 分享
发布于 2017-09-11 10:13
你的第二题是完全ac了吗
点赞 回复 分享
发布于 2017-09-11 09:41
代码写得太烂
点赞 回复 分享
发布于 2017-09-11 00:36
亲,第一题我还是不明白呢,思路是啥样的
点赞 回复 分享
发布于 2017-09-10 23:25

相关推荐

每晚夜里独自颤抖:这个在牛客不是老熟人了吗
点赞 评论 收藏
分享
评论
点赞
17
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务