2020腾讯第二次笔试(9.7)部分题解

并查集卡了好久没时间,最后一题蹭了5%

第一题

题意

两个降序链表求相同的部分。

分析

不想写链表就直接数组了,直接搞个map就行了。

参考代码

#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
const int MAXN = 1000005;

int n, m;
int a[MAXN], b[MAXN];
map<int, int> Map;

int main() {
    scanf("%d", &n);
    for (int i=1; i<=n; ++i) {
        scanf("%d", &a[i]);
        Map[a[i]] = 1;
    }
    scanf("%d", &m);
    for (int i=1; i<=m; ++i) {
        scanf("%d", &b[i]);
        if (Map.count(b[i])) {
            printf("%d ", b[i]);
        }
    }
    printf("\n");
    return 0;
}

第二题

题意

有n个人编号可能会出现0-n里面的数字,m个小组。有一个事情会告诉0号,然后0号会告诉他们小组的其他人,然后其他人在告诉有他们的小组的其他人,然后问最后有多少人知道这个事情。

分析

经典并查集,一直20%,最后发现编号是0 ~ n,不是0 ~ n-1。。。。
据说是改了题目?实在是太坑了,卡了我至少半个小时。

参考代码

#include <cstdio>
#include <iostream>
using namespace std;

int fa[1000005];
int t[10005];
int n, m;

inline int find(int x) {
	if (fa[x] == x) return x;
	else return fa[x] = find(fa[x]);
}

inline void combine(int x, int y) {
	int fx = find(x), fy = find(y);
	if (fx==fy) return;
	fa[fx] = fy;
}

int main() {
	while(cin >> n >> m) {
		for (int i=0; i<=n; ++i) {
			fa[i] = i;
		}
		for (int i=0; i<m; ++i) {
			int x;
			scanf("%d", &x);
			for (int j=0; j<x; ++j) {
				scanf("%d", &t[j]);
				if (j!=0) combine(t[j], t[j-1]);
			}
		}
		int ans = 0;
		for (int i=0; i<=n; ++i) {
			if (find(i) == find(0)) {
				ans++;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

第三题

题意

给n个字符串,根据字符串出现次数排序,求前k个出现次数最多的,和前k个出现次数最少的,如果出现次数一样,都按照字典序排列。
样例输入:

4 2
1
2
3
4

样例输出:

1 1
2 1
1 1
2 1

分析

直接写两个排序,排完输出就完事了。

参考代码

#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <unordered_map>
using namespace std;

int n, k;
unordered_map<string, int> M;

struct node {
	string str;
	int num;
};
string a[100005];
node b[100005];

bool cmp1(node x, node y) {
	if (x.num == y.num) return x.str < y.str;
	return x.num > y.num;
}

bool cmp2(node x, node y) {
	if (x.num == y.num) return x.str < y.str;
	return x.num < y.num;
}

int main() {
	scanf("%d%d", &n, &k);
	for (int i=1; i<=n; ++i) {
		cin >> a[i];
		M[a[i]]++;
	}
	int sum = 0;
	for (int i=1; i<=n; ++i) {
		if (M[a[i]] != -1) {
			++sum;
			b[sum].str = a[i];
			b[sum].num = M[a[i]];
			M[a[i]] = -1;
		}
	}
	sort(b+1, b+1+sum, cmp1);
	for (int i=1; i<=k; ++i) {
		cout << b[i].str << " " << b[i].num << endl;
	}
	sort(b+1, b+1+sum, cmp2);
	for (int i=1; i<=k; ++i) {
		cout << b[i].str << " " << b[i].num << endl;
	}
	return 0;
}

第四题

题意

给一个偶数长度的序列,求删除其中每一个数之后的中位数各是多少。
样例输入:

6
1 2 3 4 5 6

样例输出:

4
4
4
3
3
3

分析

显然如果是排序好的序列,前半部分删除之后的中位数就是第n/2+1位,后半部分就是n/2位,如样例。
因此可以先记录每个数的位置,然后按照大小排序,然后得到中位数之后,再重新按照位置排序输出结果即可。

参考代码

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int n, x;

struct node {
	int id, val, ans;
};
node a[200005];

bool cmp1(node x, node y) {
	return x.val < y.val;
}

bool cmp2(node x, node y) {
	return x.id < y.id;
}

int main() {
	scanf("%d", &n);
	for (int i=1; i<=n; ++i) {
		scanf("%d", &a[i].val);
		a[i].id = i;
	}
	// 大小排序
	sort(a+1, a+1+n, cmp1);
	// 求中位数
	for (int i=1; i<=n/2; ++i) {
		a[i].ans = a[n/2+1].val;
	}
	for (int i=n/2+1; i<=n; ++i) {
		a[i].ans = a[n/2].val;
	}
	// 序号排序
	sort(a+1, a+1+n, cmp2);
	for (int i=1; i<=n; ++i) {
		printf("%d\n", a[i].ans);
	}
	return 0;
}

第五题

题意

有两个颜色红和黑,每种颜色各有n个数字,给一个带颜色的数字序列,可以相邻交换,要求最后数字序列相同颜色的数字要升序,求最少的次数。

分析

因为n很小,写了个n方的做法,但是不对,等一手其他人的做法。

猜你喜欢

转载自blog.csdn.net/Radium_1209/article/details/108439336