小红书开发笔试题解

总体还是比较易,70分钟ak..(代价是鸽了今天的acm预选赛)
4个题,都是现场ac代码一点没改,不怎么好看。

第一题,给出用户的关注,互相关注的人在一个圈子里,并且有传递性。问总计有几个圈子。
裸并查集,或者忽视单向边跑一遍图有几个连通块,都是线性(并查集是接近线性)的复杂度。
#include <bits/stdc++.h>
using namespace std;
#define LL long long
int u[1005];
void init(int size)
{
	for (int i = 0; i < size; i++) u[i] = -1;
}
int find(int x)
{
	if (u[x] < 0) return x;
	u[x] = find(u[x]);
	return u[x];
}
void mix(int x, int y)
{
	if ((x = find(x)) == (y = find(y))) return;
	if (u[x] < u[y])
		u[x] += u[y], u[y] = x;
	else
		u[y] += u[x], u[x] = y;
}

int main()
{
	int i, j;
	int n;
	while (~scanf("%d", &n))
	{
		init(n);
		int temp;
		for (i = 0; i < n; i++)
			for (j = 0; j < n; j++)
			{
				scanf("%d", &temp);
				if (temp == 1)
					mix(i, j);
			}
		int ans = 0;
		for (i = 0; i < n; i++)
			if (u[i] < 0)
				ans++;
		printf("%d\n", ans);
	}
	return 0;
}
第二题,字符串的处理,删除所有括号内的内容(可能嵌套但一定成对),然后有<的删除它和它的前一个字符(如果有的话)
按照题意模拟就行..
#include <bits/stdc++.h>
using namespace std;
#define LL long long
char s[10005];
char ss[10005];
int main()
{
	int i, j;
	while (~scanf("%s", s))
	{
		int count = 0;
		j = 0;
		for (i = 0; s[i]; i++)
		{
			if (s[i] == '(')
				count++;
			if (count == 0)
				ss[j++] = s[i];

			if (s[i] == ')')
				count--;
		}
		j = 0;
		for (i = 0; ss[i]; i++)
		{
			if (ss[i] == '<')
			{
				j--;
				j = max(0, j);
				continue;
			}
			ss[j++] = ss[i];
		}
		ss[j] = 0;
		puts(ss);
		
	}
	return 0;
}
第三题,给一个数组,从中取出一些数,保证取出的数位置不连续,和最大,且和最大的里取到的数的数目最少。问和多少,取几个数。数据范围1000
肯定往动态规划上想..(都是正数的话或许贪心也可?)
dp[i][j]表示最后一个取i,总计取了j个时的总和,有dp[i][k + 1] = max(dp[i][k + 1], dp[j][k] + a[i]),j取0到i-2,k取0-i。
这是O(n^3)的复杂度,不一定能过,但是有几个剪枝:都是正数的话,为了总和最大不可能连续空3个或以上,j只有3种取值(忘记题目是不是说都是正数了..),不连续取k一定小于等于i/2+1。
其实O(n^3)就能过...
开始想着用la数组记录父节点,能少一维,没啥必要..就申请了初始化了但没用
#include <bits/stdc++.h>
using namespace std;
#define LL long long
int dp[1005][1005], la[1005];
int a[1005];
int main()
{
	int i, j, k;
	int n;
	while (~scanf("%d", &n))
	{
		memset(dp, 0, sizeof(dp));
		memset(la, -1, sizeof(la));
		for (i = 0; i < n; i++)
			scanf("%d", a + i);
		dp[0][1] = a[0];
		dp[1][1] = a[1];
		for (i = 2; i < n; i++)
			for (j = 0; j < i - 1; j++)
				for (k = 0; k <= i / 2 + 1; k++)
				{
					dp[i][k + 1] = max(dp[i][k + 1], dp[j][k] + a[i]);
				}
		int ma = 0, co = 1005;
		for (i = 0; i < n; i++)
			for (j = 0; j < n; j++)
			{
				if (dp[i][j] > ma || (dp[i][j] == ma && j < co))
					ma = dp[i][j], co = j;
			}
		printf("%d %d\n", ma, co);
	}
	return 0;
}

第四题,相当于给n个二维坐标,求最长不减折线最多经过多少个点。1e6范围。
开始以为是nlogn的最长上升子序列,快写完才发现和顺序没有关系..(然而就算是最长上升子序列也不对
不限复杂度就dp一下,n^2时间,但是1e6肯定8行。
考虑降维,对坐标的xy排序,这样每个点x值一定大于等于它前面所有的点x,就可以无视x值只看y值了。
然后按照dp的思想,dp[i]=max(dp[j])+1,j<i且j.y≤i.y。
所以维护一个数组a,a[i]表示当前最后一个点纵坐标为i的序列的最大长度。
需要logn的查询区间最大值和更新,套个线段树就行。
注意数组a大小不是n,是纵坐标最大值。(还好纵坐标给的小,不然害得套个哈希)
一个大坑,给的数据范围是大于0,然而有等于0的数据,导致运行错误..所以代码里对所有y值加一。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
struct poi { int x, y; }a[1000005];

struct { int l, r, n; }t[1000005 << 2];
void build(int l, int r, int i)
{
	t[i].l = l, t[i].r = r, t[i].n = 0;
	if (l == r)
		return;
	int mid = (l + r) >> 1;
	build(l, mid, i << 1), build(mid + 1, r, i << 1 | 1);
}
void update(int i, int x, int k)
{
	t[k].n = max(t[k].n, x);
	if (t[k].l == t[k].r)
		return;
	int mid = (t[k].l + t[k].r) >> 1;
	if (i <= mid)
		update(i, x, k << 1);
	else
		update(i, x, k << 1 | 1);
}
int sea(int l, int r, int k)
{
	if (t[k].l == l && t[k].r == r)
		return t[k].n;
	int mid = (t[k].r + t[k].l) >> 1;
	if (r <= mid)
		return sea(l, r, k << 1);
	if (l > mid)
		return sea(l, r, k << 1 | 1);
	return max(sea(l, mid, k << 1), sea(mid + 1, r, k << 1 | 1));
}
int cmp(poi a, poi b)
{
	if (a.x == b.x)
		return a.y < b.y;
	return a.x < b.x;
}
int main()
{
	int i, j, k;
	int n;
	while (~scanf("%d", &n))
	{
		int ma = 0;
		for (i = 1; i <= n; i++)
		{
			scanf("%d%d", &a[i].x, &a[i].y);
			a[i].y++;
			ma = max(ma, a[i].y);
		}
		sort(a + 1, a + n + 1, cmp);
		build(1, ma, 1);
		for (i = 1; i <= n; i++)
		{
			int temp = sea(1, a[i].y, 1);
			update(a[i].y, temp + 1, 1);
		}
		printf("%d\n", sea(1, ma, 1));
	}
	return 0;
}



#题解##小红书#
全部评论
大佬
点赞 回复 分享
发布于 2019-09-14 17:03
tql
点赞 回复 分享
发布于 2019-09-14 17:05
这是大佬。我算法A了2.1/3...感觉已凉
点赞 回复 分享
发布于 2019-09-14 17:06
大佬tql
点赞 回复 分享
发布于 2019-09-14 17:08
大佬
点赞 回复 分享
发布于 2019-09-14 17:09
AC了三道,最后一道题没时间了,瞎几把输出3通过了18🤣
点赞 回复 分享
发布于 2019-09-14 17:17
大佬tql 最后两题不会
点赞 回复 分享
发布于 2019-09-15 10:21
大佬,第三题的第22行dp[i][k + 1] = max(dp[i][k + 1], dp[j][k] + a[i]); 是不是应该是dp[i][k + 1] = max(dp[i-1][k], dp[j][k] + a[i])????求解答
点赞 回复 分享
发布于 2019-09-15 15:00
第三题,不连续子数组最大和那个,三重循环最内层 for (k = 0; k <= i / 2 + 1; k++) 是不是应该改成 for (k = 0; k <= i / 2 + 1 && k<=j; k++) k>j的时候 dp[j][k]没有意义啊😂
点赞 回复 分享
发布于 2019-09-17 15:56

相关推荐

牛客717484937号:双飞硕没实习挺要命的
点赞 评论 收藏
分享
点赞 28 评论
分享
牛客网
牛客企业服务