腾讯 秋招 2023.09.15 编程题目与题解(研发岗)
1、牛妹的数链们
牛妹有一堆数链,这些数链里面的数字都杂乱无章,牛妹想整理一下这世数字,把它们从小到大排成一个数链。
样例
1 | 输入: |
备注
- \(0\le val\le 10^9\)
- 总元素个数\(\le 10^5\)
解答
这里仅提供一种最暴力的做法:将所有节点都存在数组中,排完序后重新成链。
代码
1 | class Solution{ |
2、小Q的奇偶操作数组
小Q有一个长度为\(n\)的数组,它对这个数组有\(k\)次操作机会,操作如下:
可以选择数组中的任意一个数字并改变它。
- 如果选择的数字\(x\)是奇数,那么这个奇数乘以\(2\),即\(x=x\ast2\)
- 如果选择的数字\(x\)是偶数,那么这个偶数乘以\(2\)再加\(1\),即\(x=x\ast 2+1\)
小Q想让这\(k\)次操作之后,数组元素之和最小,请你输出这个最小值是多少?
保证最终的元素之和不超过\(10^{18}\)。
输入
第一行两个正整数\(n\)和\(k\),用空格隔开。
第二行输入\(n\)个正整数\(a_i\),每个\(a_i\)代表数组的元素。
- \(1\le n\le 200000\)
- \(1\le k\le 200000\)
- \(1\le a_i\le 10000000\)
输出
输出一个整数,代表\(k\)次操作之后,数组元素之和的最小值。
样例
1 | 输入: |
解答
每次只需要取出数组中最小的元素值进行操作即可。我们可以使用贪心选择性质如下证明:
假设现在数组中,最小元素是\(x\),而选择的元素是\(y\),并且满足\(y>x\)。那么哪怕\(y\)是偶数,\(x\)是奇数,最终得到的数组和的差值满足\(2y-(2x+1)=2(y-x)-1>0\),也就是说,只要选择了\(y\),最终得到的一定不是最优解。
每次寻找最小的数这个过程我们可以使用最小堆来完成。
代码
1 |
|
3、赛道
牛牛组织了一场拉力赛,在一条水平的赛道上,共有\(n\)辆赛车,在当前时刻,牛牛记录下来了从左到右每辆车的位置\(p_1,p_2,\dots,p_n(0 \le p_1 < p_2 < \dots < p_n)\),假设起点处位置为\(0\),因此它们当前的排名依次为: \(n,n-1,n-2,\dots,1\)。现在牛牛知道在位置\(p_i\)处的车辆速度为\(v_i\),假设所有的车保持匀速行驶,牛牛想知道在\(t\)个单位时间后,有多少赛车的排名上升?
注:如果在\(t\)个单位时间后有两辆车的位置相同,则这两辆车的排名相同。一辆车的排名为在它前面的车辆的个数加\(1\)。
输入
第一行输入两个正整数\(n,t\)。
第二行输入\(n\)个由空格隔开的整数\(p_1,p_2,\dots,p_n\)。
第三行输入\(n\)个由空格隔开的整数\(v_1,v_2,\dots,v_n\)。
- \(1\le n\le 10^5,0\le p_i\le 10^5,1\le v_i\le 100,1\le t\le 1000\)
输出
输出\(t\)个单位时间之后排名上升的赛车数量。
样例
1 | 输入: |
解答
为了编码方便,我们重新将排名定义成:当前距离在它后面的车辆的个数加\(1\),也就意味着这个排名数值越大越好。
计算出\(s_i=p_i+v_i\cdot t\)后,对原本所有的赛车重新进行排名。如果新排名的数值比原来高,那么就对其进行统计即可。这里需要注意的是新排名需要仔细处理距离相同的情况。
代码
1 |
|
4、旋转串
对于一个字符串,如果把字符串的第一个字符放到最后,得到的新串就是原来字符串的旋转串。
一个字符串的旋转串的旋转串也是这个字符串的旋转串。即这种关系具有传递性。
例如abc
的旋转串有:bca cab abc
如果存在一个字符串,既是\(x\)的旋转串也是\(y\)的旋转串,那么我们称\(x,y\)匹配。
请回答一系列字符串中是否有两个字符串匹配。
输入
第一行输入一个正整数\(T\),表示输入数据的组数。
每组数据第一行为一个正整数\(n\)。
接下来\(n\)行,每行一个只含小写字母的字符串\(s\)。
- \(1\le T\le 50,1\le n\le 5000\)
每个字符串的长度都相同且不会超过\(50\)
输出
如果存在两个字符串匹配,则输出YES
,否则输出NO
。
样例
1 | 输入: |
解答
如果\(x\)和\(y\)匹配,那么意味着\(x\)串可以旋转操作得到\(y\)。此时,\(x\)通过旋转得到的最小字典序的字符串和\(y\)通过相同操作得到的字符串相同。
因为,我们求出每个字符串的最小旋转串,然后再判断是否有两个最小旋转串是否相同即可。
其中,求最小旋转串只需要暴力旋转每个字符串即可。
代码
1 |
|
5、红点和蓝点
有\(n\)个点,第\(i\)个点的坐标为\(x_i\),第\(i\)个点的颜色为\(c_i\)。
如果\(c_i=0\),则第\(i\)个点为红点。
如果\(c_i=1\),则第\(i\)个点为蓝点。
每次你可以做以下两种操作之一:
- 选择一个红点,设这个红点的坐标为\(x\),把这个点移动到\(x-1\)或\(x+1\)。
- 选择一个蓝点,将它变为红点。
你可以最多做\(k\)次操作2。求最少要进行多少次操作1可以使得意两个红点之间不存在蓝点。
即设两个红点分别在坐标\(x,y(x \le y)\),则不存在任何一个蓝点的坐标在区间\([x,y]\)内。
输入
第一行两个整数\(\displaystyle{n,k(1\le n\le 200000,0\le k\le \sum_{i=1}^n c_i)}\)。
第二行\(n\)个整数\(x_1,x_2,\dots ,x_n(1\le x_1\le x_2\le \dots \le x_n \le 10^9)\)。
第三行\(n\)个整数\(c_1,c_2,\dots ,c_n(0\le c_i\le 1)\).
输出
输出一行一个整数表示答案。
样例
1 | 输入: |
解答
首先我们可以证明:如果要对蓝点染成红色,那么这些蓝点一定是相邻的。否则,将两块不相邻的蓝点染成红色后,还要将其中一块移动到中间间隔开的蓝点的另一端,这时还不如不对一块蓝点染色。因此,我们只考虑将连续一块的蓝点染成红色。
接下来我们使用双指针法来接解决这个问题。枚举每个点作为右端点\(r\),找到一个最小的\(l\)使得区间\([l,r]\)内至多包含\(k\)个蓝色节点。那么我们只需要将区间外的节点移动到坐标范围\((x_{l-1},x_{r+1})\)即可(如果区间为空,那么我们不讨论)。这时,在这个区间左侧的所有节点都移动到坐标\(x_{l-1}+1\),在这个区间右侧的坐标都移动到\(x_{r+1}-1\)即可。因此,其中一个候选答案为:
\[\sum_{x_i\le x_{l-1}} (x_{l-1}+1-x_i)+\sum_{x_i\ge x_{r+1}} (x_i-(x_{r+1}-1))\]
我们最终还要算上区间\((-\infty,x_1)\)和\((x_n,\infty)\)的情况,最终一共有\(n+1\)个候选答案,选其中一个最优即可。
代码
1 |
|