腾讯 秋招 2023.09.10 编程题目与题解(研发岗)
1、路径偏差数量
牛牛有一棵二叉树,该二叉树节点的权值为\(0/1\)。
牛牛给你这棵二叉树,想让你告诉他该二叉树从根节点到叶子节点的所有路径中,节点"权值\(1\)的个数"比"权值\(0\)的个数"多\(1\)的路径有多少条呢。
返回路径数目。
样例
1 | 输入: |
第一个样例如下图所示:
graph TD A((1));B((0));C((0));D((1)); E((0));F((1));X(( )); A---B;A---C;B---D;B---E; C---X;C---F; style X fill:#f100,stroke-width:0px linkStyle 4 stroke:#0ff,stroke-width:0px
解答
直接通过深度优先搜索遍历每个叶子节点,然后判断当前路径下权值\(1\)的节点个数是否恰好比节点\(0\)的个数多\(1\)即可。
代码
1 | class Solution{ |
2、删除中位数
牛牛有一个长度为\(n\)的序列\(a\),以及一个长度为\(n-1\)的序列\(b\),序列\(b\)中的元素不重复。
对于这个序列\(a\)牛牛会先求出他的中位数,然后再根据序列\(b\)的顺序依次删除原序列\(a\)中对应下标的元素,即删除\(a[b[i]],0\le i<n-1\)。
每次删除完一个数后,牛牛会统计序列\(a\)中剩下的数的中位数是什么,若剩下的数为奇数牛牛会取中间数(排序后),若为偶数牛牛会取中间两个数的平均值(排序后)。
牛牛把每次的结果都记录下来了,但是他怕出错,给你初始的序列\(a\)和\(b\),希望你能帮他验证一下。
输入
第一行为一个\(t\),表示有\(t\)组数据。
接下来有\(3 \times t\)行,每组数据的第一行为\(n\)表示序列长度。
第二行为\(n\)个整数,表示序列\(a\)的元素。
第三行为\(n-1\)个整数,表示序列\(b\)的元素。
输出
输出为\(t\)行,每行有\(n\)个整数,表示每组数据的答案,其中输出若是浮点数保留小数点后一位,否则按整数输出。
样例
1 | 输入: |
解答
我们可以考虑使用对顶堆来完成这个过程的求解。它的具体过程是:用一个最大堆维护目前拥有的较小数,用一个最小堆维护目前拥有的较大数。并且这两个堆的大小相差不超过\(1\)。此时,如果两个堆如果元素总和是奇数,那么取较多元素的那个堆的堆顶即为中位数,否则取两个堆的元素作为平均值。
但是呢,这题是将数组中的元素逐个删去,用对顶堆似乎不行。解决方法是:对整个操作逆向,从而整个过程都是在添加数,这时使用对顶堆可以完成。
代码
1 |
|
3、勇敢牛牛不怕困难
有\(n\)个怪物,第\(i\)个怪物的战斗力为\(a_i\),初始时,牛牛的战斗力为\(0\)。
牛牛要与这\(n\)个怪物战斗,设牛牛与第\(i\)个怪物战斗时牛牛的战斗力为\(x\),则:
若\(x<a_i\),则牛牛触发被动技能"勇敢牛牛不怕困难"使得自己的战斗力提升至\(a_i\)并战胜这个怪物,这会让牛牛的勇气值提升\(a_i-x\) 。
若\(x\ge a_i\),则牛牛会直接战胜这个怪物,并且本次战斗结束后,牛牛的战斗力会降低至\(a_i\)。
牛牛可以任意决定与怪物战斗的顺序,牛牛想知道打败完所有的\(n\)只怪物之后,牛牛累计提升的勇气值最大可能是多少。
输入
第一行一个整数\(n(1\le n\le 200000)\)。
第二行\(n\)个整数\(a_1,a_2,\dots, a_n(1 \le a_i\le 10^9)\)。
输出
输出一个整数表示牛牛可以得到的最大勇气值。
样例
1 | 输入: |
解答
为了获得更多的勇气值,我们最佳的做法是:
在自身战斗力最低的时候去击败战斗力最高的怪物,这样能够使自身的勇气值上升最快。在自身攻击力最高的时候击败攻击力最低的怪物,这样能够使自身的战斗力下降的最快。
因此最优的做法是先打最高战斗力的怪物,再打对低战斗力的怪物,反复如此即可达到最大勇气值。
代码
1 |
|
4、校验和
差错控制是计算机网络数字传输中重要的一环。
假设传输的数据以一个长度为\(n\)的二进制位串\(S\)表示,牛牛定义了一种新的校验和,他将\(S\)中所有长度为的子串进行异或,得到的新串就是他定义的校验和。
例如,对于位串\(000111\)来说,当\(k\)为\(2\)时,所有的长度为\(2\)的子串为\(00,00,01,11,11\),将他们对应的位异或,得到的校验和为\(01\)。
然而他定义的校验和实际上难以进行好的差错控制,为了验证,牛牛决定计算在上述定义的方式下,有多少个不同的"长度为\(n\)"且"与\(S\)不同的二进制位串"可以产生"与\(S\)相同"的校验和。
子串的定义:一个串中任意个连续的字符组成的子序列。显然最终的结果与\(S\)无关,由于答案可能过大,请输出结果对\(10^9+7\)取模后的结果。
输入
第一行一个正整数\(T\),代表测试组数。
接下来\(T\)行每行以空格分隔的两个正整数\(n,k\)。
- \(1\le T\le 10^5\)
- \(1\le k\le n\le 10^6\)
输出
输出\(T\)行,每行一个整数代表答案。
样例
1 | 输入: |
解答
由于题目已经讲明了结果和字符串\(S\)本身是无关的,因此每个检验结果都有相同的串对应它。由于检验结果只有\(2^k\)种,因此有\(2^{n-k}\)个不同的字符串对应着当前结果,也就是说对于字符串\(S\)而言,有\(2^{n-k}-1\)个不同字符串和它有着相同的检验结果。
代码
1 | T = int(input()) |
5、牛妹的\(k\)次奇怪操作
牛妹有一个序列\(a_1,a_2,\dots,a_n\),牛妹可以执行次操作。每次操作步骤如下:
- 牛妹选择一个\(pos(1\le pos\le n)\)
- 将\(a_{pos}\)在二进制下最低位的\(1\)变成\(0\)
牛妹想知道\(k\)次操作后序列之和的最小值为多少?
输入
第一行输入两个整整数\(n,k\)
接下来输入\(n\)个正整数,表示牛妹的序列
- \(1\le n \le 10^5,1\le k\le 100,1 \le a_i \le 10^9\)
输出
输出一个数,代表答案。
样例
1 | 输入: |
解答
这题是一道动态规划题目,过程非常明显:令状态\(f(i,j)\)表示对前\(i\)个数执行了至多\(j\)次操作后,这前\(i\)个元素的最小和值。
我们假设\(b_{i,j}\)表示对数组元素\(a_i\)执行了\(j\)次操作后的值。不难发现:
\(b_{i,0}=a_i\),如果\(b_{i,j-1}=0\),那么\(b_{i,j}=0\)。此外,由于\(a_i\le 10^9\),因此\(j\)必定存在一个上限\(m\),我们设其为\(m=30\)。
因此,我们不难写出\(f(i,j)\)的状态转移方程为:
\(f(i,j)= \left \{\begin{aligned} &0 & & \text{if}\quad i=0 \\ &\min_{0\le l\le j,0\le l\le m}\{f(i-1,j-l)+b_{i,l}\} & & \text{if}\quad i > 0 \end{aligned}\right.\)
其中方程第二行表示对数\(a_i\)执行了\(k\)次操作后,从\(f(i-1,j-l)\)转移而来,并得到了\(b_{i,l}\)的和。
因此本题的最终答案为\(f(n,k)\)。
代码
1 |
|