奇安信 秋招 2023.09.16 编程题目与题解
1、资深彩民的投注方案
纳西姆·塔勒布在著作《随机漫步的傻瓜》中提到过“赌徒谬误”:赌徒谬误的产生是因为人们错误的诠释了“大数法则”的平均律,以为随机序列中一个事件发生的机会率与发生的事件有关,即其发生的机会率会随着之前没有发生该事件的次数而上升。如重复抛一个公平硬币,而连续多次抛出反面朝上,赌徒可能错误地认为,下一次抛出正面的机会会较大。
很遗憾的是,资深彩民小王沉迷于此,现在有一批双色球的往期中奖号码数据,小王想要从其中找到出现次数最少的几个数字进行投注。现在已知双色球每期会有产生\(7\)个中奖号码,号码从\(1\text{-}33\),不会重复。例如往期某次的中奖号码为: \([5,10,13,20,25,27,30]\),请帮助小王完成这个分析程序,输入是往期的中奖号码数组,请输出一组符合小王需求的投注方案。
其它要求:
- 将投注方案中的数字按照从小到大排列。
- 如果存在多组可能,比如有\(8\)个数字出现次数都是\(0\),那么把数字最小的\(7\)个数字组成一组投注方案输出。
样例
1 | 输入: |
解答
本题思路比较简单,先统计当前所有中奖号码都出现的次数,然后对\(1\sim 33\)这\(33\)个号码按照以第一关键字为出现频率,升序;第二关键字为数值本身,升序进行排序。最终取排序结果的前\(7\)个号码即可。
取出这\(7\)个号码后,还要对它们进行排序后返回。
代码
1 | class Solution{ |
2、卡片游戏
小朋友们在玩一款卡片游戏,卡片一共有\(N\)张,每张上印有\(0\)到\(N-1\)的互不重复数字,作为卡片的唯一编号。将\(N\)张卡片按照树形结构排列,提问的小朋友说出一张卡片的编号\(a\)和数字\(b\),另一个小朋友需要从卡片编号\(a\)到树的根节点路径上找出一张卡片\(c\),该卡片\(c\)的编号与数字\(b\)的异或值最大。
\(\texttt{parents}[i]\)表示卡片编号\(i\)的父节点的卡片编号。如果节点\(x\)是树的根节点,则\(\texttt{parents}[x] = -1\)。
\(\texttt{questions}[i] =[\texttt{node}_i,\texttt{val}_i]\)表示第\(i\)个问题,卡片的编号为\(\texttt{node}_i\),说出的数字为\(\texttt{node}_i\),需要找到卡片\(p_i\),使得\(\texttt{val}_i\)和\(p_i\)的异或值最大,其中\(p_i\)是\(\texttt{node}_i\)到根之间的节点(包含\(\texttt{node}_i\)和根节点),即需要最大化\(\texttt{val}_i\text{ XOR }p_i\)。
请返回数组result ,其中\(\texttt{result}[i]\)是第\(i\)个问题的答案。
说明:\(2\le N\le 10^5,0\le b \le 2\times 10^5\)
输入
第一行为\(\texttt{parents}\)数组,表示树的结构,使用逗号分割的整数。
- \(2 \le \texttt{parents.length} \le 10^5\)
对于每个不是根节点的\(i\),有 \(0 \le \texttt{parents}[i] \le \texttt{parents.length} - 1\)。
之后\(M\)行为数组,每行表示提出的一个问题,包括两个整数\(\texttt{node}_i\)和\(\texttt{val}_i\),使用逗号分割。
- \(1\le \texttt{questions.length}\le 3*10^4\)
- \(0 \le \texttt{node}_i \le \texttt{parents.length} - 1\)
- \(0 \le \texttt{val}_i \le 2\times10^5\)
- \(1\le M\le 3\times10^4\)
输出
\(M\)个用逗号分割的整数,为对应问题的答案。
样例
1 | 输入: |
以下是这两棵树对应的图:
graph TD subgraph T1 A((0));B((1));C((2));D((3)); B---A;A---C;A---D; end subgraph T2 0((0));1((1));2((2));3((3)); 4((4));5((5));6((6));7((7)); 2---7;2---0;7---1;7---5; 0---3;3---4;3---6; end
解答
这题是字典树运用的经典例题。我们首先考虑如下问题:
问题一:给定一个整数集合\(S\)以及多个询问,每次询问给出一个数\(x\),问\(S\)中和\(x\)异或产生的最大结果是多少?
我们使用字典树解决,对\(S\)中的所有数看成是一个\(M\)比特数,并从高位到地位插入字典树中。询问\(x\)时,假设从高到低遍历到\(x\)的某一比特\(b\),然后在当前节点查看是否能去到另一侧的节点(也就是由\(1-b\)指向的节点),如果能去,那么当前位对答案会有贡献;否则只能走向当前的节点,无法对答案做出贡献。由于最高位优先,因此产生的是一个最佳答案。
那么现在对问题一加一些操作,得到一个更复杂的问题:
问题二:集合\(S\)可以动态增加/删除元素(且保证询问时非空),如何处理?
我们可以在这棵字典树上对每个节点进行标记,这些标记可以叠加和撤销。在询问时,如果\(1-b\)指向的节点没有标记(或者是不存在),那么说明只能走去另一侧的节点,否则可以走上另一侧的节点。
本问题是问题二的一个特例。使用深度优先搜索遍历到某个节点\(u\)时,将\(u\)这个值插入到集合\(S\)中,此时将和关联节点\(u\)的所有询问完成后,遍历它的所有子节点,最终将\(u\)从\(S\)中删除即可。
剩下的则是一些麻烦的处理输入输出问题,此处不赘述。
代码
1 |
|