大厂真题

华为研发岗 2026-09-09

本场考试概述

考试时间:2026-9-9 考试岗位:研发岗 难度评级:中等偏难

考点分析

  • 第一题 5G基站部署的双向干扰指数计算:单调栈 (难度中等)
  • 第二题 挑选奖品:背包DP (难度中等)
  • 第三题 网络流量路径规划:有向图欧拉路径 Hierholzer (难度困难)

建议策略

  • 三道题都是经典模型换了层业务外壳,先把题面翻译成模型再动手:找最近的更大元素就是单调栈、限件数限金额挑方案就是二维背包、每条边走一次就是欧拉路径
  • 第一题的 k 是个纸老虎,先无视它求全局最近更大者,最后拿距离和 k 比一次即可,别真的每个位置往两边扫 k 格
  • 第三题不要凭直觉每步挑字典序最小的目标,那样会中途走死;必须用 Hierholzer 后序压栈、结果逆序输出,而且要写显式栈防爆栈

第 1 题:5G基站部署的双向干扰指数计算

题目描述

数学公式(保留原始 SVG) 网络规划中,需要在一条直线上的若干位置部署基站。现给定每个位置 数学公式(保留原始 SVG) 的基站信号强度为 数学公式(保留原始 SVG)。针对每个基站,需要计算其受到左右两边相邻基站的干扰影响。

对于每个基站 数学公式(保留原始 SVG),定义:

  1. 左侧干扰区间:在数组范围内,从位置 数学公式(保留原始 SVG) 开始向左搜索(索引递减),最多搜索 数学公式(保留原始 SVG) 个基站。
  2. 右侧干扰区间:在数组范围内,从位置 数学公式(保留原始 SVG) 开始向右搜索(索引递增),最多搜索 数学公式(保留原始 SVG) 个基站。
  3. 左侧干扰指数:在左侧干扰区间内,寻找第一个(即最近一个)信号强度严格大于 数学公式(保留原始 SVG) 的基站位置 数学公式(保留原始 SVG)。若找到,则贡献值为 数学公式(保留原始 SVG);若未找到(即在搜索范围内无更强信号),则左侧贡献值为 数学公式(保留原始 SVG)(即取 数学公式(保留原始 SVG))。
  4. 右侧干扰指数:在右侧干扰区间内,寻找第一个(即最近一个)信号强度严格大于 数学公式(保留原始 SVG) 的基站位置 数学公式(保留原始 SVG)。若找到,则贡献值为 数学公式(保留原始 SVG);若未找到,则右侧贡献值为 数学公式(保留原始 SVG)(即取 数学公式(保留原始 SVG))。
  5. 总干扰指数:所有基站的左侧干扰指数与右侧干扰指数之和。

请计算并输出基站的总干扰指数。

输入描述

第一行包含 数学公式(保留原始 SVG) 所有基站的信号强度,以空格分隔,长度记为 数学公式(保留原始 SVG),每个元素满足 数学公式(保留原始 SVG),如 3 1 4 2 5。

第二行包含一个整数 数学公式(保留原始 SVG),表示连续搜索的基站数量,如 3。

题目保证输入合法,无需校验输入。

输出描述

一个整数,基站的总干扰指数,输出结果对 数学公式(保留原始 SVG) 取模。

样例1

输入

7 2 5 3 9 4 6 1 8 3
5

输出

127

样例解释

以基站 数学公式(保留原始 SVG)(强度 数学公式(保留原始 SVG))为例,左侧没有基站,左侧干扰为 数学公式(保留原始 SVG);右侧依次查看索引 数学公式(保留原始 SVG)数学公式(保留原始 SVG),强度为 数学公式(保留原始 SVG),前三个都不超过 数学公式(保留原始 SVG),直到索引 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 严格大于 数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),右侧干扰为 数学公式(保留原始 SVG),合计 数学公式(保留原始 SVG)

以基站 数学公式(保留原始 SVG)(强度 数学公式(保留原始 SVG))为例,左侧查看索引 数学公式(保留原始 SVG)数学公式(保留原始 SVG),严格大于 数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),左侧干扰为 数学公式(保留原始 SVG);右侧查看索引 数学公式(保留原始 SVG)数学公式(保留原始 SVG),严格大于 数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),右侧干扰为 数学公式(保留原始 SVG),合计 数学公式(保留原始 SVG)

以基站 数学公式(保留原始 SVG)(强度 数学公式(保留原始 SVG))为例,左侧依次查看索引 数学公式(保留原始 SVG),强度为 数学公式(保留原始 SVG),直到 数学公式(保留原始 SVG) 严格大于 数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),左侧干扰为 数学公式(保留原始 SVG);右侧依次查看索引 数学公式(保留原始 SVG),强度为 数学公式(保留原始 SVG),直到 数学公式(保留原始 SVG) 严格大于 数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),右侧干扰为 数学公式(保留原始 SVG),合计 数学公式(保留原始 SVG)

十个基站的干扰指数依次为 数学公式(保留原始 SVG),总和为 数学公式(保留原始 SVG),对 数学公式(保留原始 SVG) 取模仍为 数学公式(保留原始 SVG)

样例2

输入

3 1 4 2 5
3

输出

20

样例解释

基站 数学公式(保留原始 SVG)(强度 数学公式(保留原始 SVG))左侧无基站干扰为 数学公式(保留原始 SVG),右侧查看 数学公式(保留原始 SVG) 中最先严格大于 数学公式(保留原始 SVG) 的是索引 数学公式(保留原始 SVG)数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),干扰为 数学公式(保留原始 SVG),合计 数学公式(保留原始 SVG)

基站 数学公式(保留原始 SVG)(强度 数学公式(保留原始 SVG))左侧的 数学公式(保留原始 SVG) 严格大于 数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),干扰为 数学公式(保留原始 SVG);右侧最先严格大于 数学公式(保留原始 SVG) 的是索引 数学公式(保留原始 SVG)数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),干扰为 数学公式(保留原始 SVG),合计 数学公式(保留原始 SVG)

基站 数学公式(保留原始 SVG)(强度 数学公式(保留原始 SVG))左侧查看 数学公式(保留原始 SVG) 都不超过 数学公式(保留原始 SVG),干扰为 数学公式(保留原始 SVG);右侧查看 数学公式(保留原始 SVG),直到 数学公式(保留原始 SVG) 严格大于 数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),干扰为 数学公式(保留原始 SVG),合计 数学公式(保留原始 SVG)

基站 数学公式(保留原始 SVG)(强度 数学公式(保留原始 SVG))左侧最先严格大于 数学公式(保留原始 SVG) 的是索引 数学公式(保留原始 SVG)数学公式(保留原始 SVG),距离为 数学公式(保留原始 SVG),干扰为 数学公式(保留原始 SVG);右侧的 数学公式(保留原始 SVG) 距离为 数学公式(保留原始 SVG),干扰为 数学公式(保留原始 SVG),合计 数学公式(保留原始 SVG)

基站 数学公式(保留原始 SVG)(强度 数学公式(保留原始 SVG))左侧查看 数学公式(保留原始 SVG) 都不超过 数学公式(保留原始 SVG),右侧无基站,合计 数学公式(保留原始 SVG)

五个基站合计 数学公式(保留原始 SVG),对 数学公式(保留原始 SVG) 取模仍为 数学公式(保留原始 SVG)

题解:单调栈

思路分析

每个基站向左、向右各找一个强度严格大于自己的最近基站,找到就把”自身强度 数学公式(保留原始 SVG) 距离”计入该侧贡献,找不到记 数学公式(保留原始 SVG),两侧搜索各限制在 数学公式(保留原始 SVG) 个基站以内。数学公式(保留原始 SVG) 个基站的贡献求和后对 数学公式(保留原始 SVG) 取模即为答案。

这是一道把”窗口内找第一个更大元素”化归成经典单调栈的题:栈本身不难写,难在说清 数学公式(保留原始 SVG) 这个窗口限制为什么可以先摘掉。

算法实现

最直白的写法是对每个 数学公式(保留原始 SVG) 向两侧各扫最多 数学公式(保留原始 SVG) 个位置,遇到更大的就停。它是 数学公式(保留原始 SVG)数学公式(保留原始 SVG)数学公式(保留原始 SVG) 时约 数学公式(保留原始 SVG) 次比较,远超时限。

再看 数学公式(保留原始 SVG) 到底约束了什么。记 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 左侧最近的严格更大者下标,数学公式(保留原始 SVG) 为右侧最近的:

数学公式(保留原始 SVG)

数学公式(保留原始 SVG)数学公式(保留原始 SVG) 落在窗口内,它正是窗口内第一个更大者;若 数学公式(保留原始 SVG),窗口 数学公式(保留原始 SVG) 整段都在 数学公式(保留原始 SVG) 右侧,而 数学公式(保留原始 SVG) 已是最近的更大者,这段里不可能还有更大的,该侧贡献必为 数学公式(保留原始 SVG)

所以先无视 数学公式(保留原始 SVG) 求全局最近的更大者,再拿距离与 数学公式(保留原始 SVG) 比一次即可。

数学公式(保留原始 SVG) 用单调栈:从左往右扫,栈里存下标、对应强度从栈底到栈顶严格递减;当前元素进栈前把栈顶强度不大于它的全部弹掉,剩下的栈顶即 数学公式(保留原始 SVG),栈空则不存在。

弹掉的位置不会是任何人的答案:它强度不超过 数学公式(保留原始 SVG),既当不了 数学公式(保留原始 SVG) 的答案,也当不了 数学公式(保留原始 SVG) 右边位置的答案,因为那些位置要越过 数学公式(保留原始 SVG) 才能看到它,而 数学公式(保留原始 SVG) 既更大又更近。每个下标进栈出栈各一次。

弹栈判据必须写成”栈顶强度 数学公式(保留原始 SVG) 当前强度”。题面要的是严格大于,写成 数学公式(保留原始 SVG) 会把等值位置留在栈里,等值基站就被误当成更强的答案。

数学公式(保留原始 SVG) 那一遍从右往左扫,其余完全对称。累加时单项最大约 数学公式(保留原始 SVG),必须用 数学公式(保留原始 SVG) 位整数并每步取模。

复杂度分析

时间复杂度:O(n)。

空间复杂度:O(n),包括输入数组与单调栈。

题解代码

import sys
input = sys.stdin.readline

def solve():
    power = list(map(int, input().split()))
    k = int(input())
    n = len(power)
    total = 0
    for indices in (range(n), range(n - 1, -1, -1)):
        stack = []
        for i in indices:
            while stack and power[stack[-1]] <= power[i]:
                stack.pop()
            if stack and abs(i - stack[-1]) <= k:
                total += power[i] * abs(i - stack[-1])
            stack.append(i)
    print(total % 1000000007)

solve()

正确性说明

扫描过程中,被弹出的下标比当前下标更远且强度不更大,不可能成为后续位置的最近严格更大者。剩余栈顶因此恰好是该侧答案;距离超过 k 时,窗口内也不存在更大者。两侧贡献相加即为所求。

易错点与边界

相等强度必须弹栈;索引从 0 开始,距离仍为下标之差。Python 整数无需手动模拟 64 位溢出。

第 2 题:挑选奖品

题目描述

小明 今年工作完成得非常好,是部门公认的优秀员工,部门准备奖励一下 小明。小明 可以从礼物清单里面选四个礼物,总价不能超过 数学公式(保留原始 SVG) 元。每个礼物都有特定编号和价格,礼物编号不会重复,价格可能重复。

小明 想挑选四个总价最接近上限的礼物,如果总价一样,就选择礼物编号按照升序排序后数值序小的那一组。

输入描述

第一行包含一个整数 数学公式(保留原始 SVG),表示礼物个数。

接下来 数学公式(保留原始 SVG) 行表示 数学公式(保留原始 SVG) 个礼物,每行两个整数 数学公式(保留原始 SVG),分别表示礼物的编号和价格。

输出描述

如果有满足要求的礼品,输出礼品编号,礼品编号之间以空格分割,礼品编号按照升序排序。如果没有满足要求的 数学公式(保留原始 SVG) 个礼物,输出 数学公式(保留原始 SVG)

样例1

输入

6
1 100
3 10000
5 5000
8 3000
7 100
9 100

输出

1 5 7 8

样例解释

编号组合 数学公式(保留原始 SVG)数学公式(保留原始 SVG)数学公式(保留原始 SVG) 这三组礼物价值之和全部是 数学公式(保留原始 SVG),且最接近 数学公式(保留原始 SVG),优选按照编号数值排序后数值序小的礼物组合,即 数学公式(保留原始 SVG)

样例2

输入

5
1 100
3 10000
5 5000
8 5000
9 9988

输出

0

样例解释

这里面找不出 数学公式(保留原始 SVG) 个礼物之和小于等于 数学公式(保留原始 SVG) 元,输出 数学公式(保留原始 SVG)

题解:背包DP

思路分析

数学公式(保留原始 SVG) 件礼物里恰好挑 数学公式(保留原始 SVG) 件,总价不超过 数学公式(保留原始 SVG) 且尽量大;总价并列时,取编号升序排好后字典序最小的那一组。

这是一道件数与金额双限制的 01 背包题:求最大总价是常规操作,难点在并列时还要把编号字典序最小的那一组方案也挑出来。

算法实现

四重枚举有 数学公式(保留原始 SVG) 种组合,数学公式(保留原始 SVG) 稍大就跑不完。换成背包:每件礼物只有选与不选两种,把件数和总价一起当限制,状态就只剩 数学公式(保留原始 SVG) 个。

先解决怎么比字典序。把一组升序编号拼成一个 数学公式(保留原始 SVG) 进制的数,编号最大 数学公式(保留原始 SVG),进位不会串到相邻位上:

数学公式(保留原始 SVG)

小编号放在高位,所以两组长度相同的编号比 数学公式(保留原始 SVG) 的大小就等于比字典序,而 数学公式(保留原始 SVG) 最大约 数学公式(保留原始 SVG),一个 数学公式(保留原始 SVG) 位整数装得下。有了它,方案本身就能塞进状态里,不必另外记录路径。

状态方程定义:礼物先按编号升序排。数学公式(保留原始 SVG) 表示恰好选 数学公式(保留原始 SVG) 件、总价为 数学公式(保留原始 SVG) 时,字典序最小的那组编号的 数学公式(保留原始 SVG),凑不出记 数学公式(保留原始 SVG)

状态方程初始化

数学公式(保留原始 SVG)

一件不选、总价为 数学公式(保留原始 SVG) 是唯一的起点,其余格子都是 数学公式(保留原始 SVG)

状态方程转移:按编号升序逐件处理,件数与总价都从大往小刷新,也就是 01 背包的倒序写法,保证每件礼物只被用一次。设当前礼物编号为 数学公式(保留原始 SVG)、价格为 数学公式(保留原始 SVG)

数学公式(保留原始 SVG)

只在 数学公式(保留原始 SVG) 时才转移。礼物按编号升序处理,数学公式(保留原始 SVG) 一定大于旧组合里的所有编号,接在末尾仍然是升序。

数学公式(保留原始 SVG) 不会丢解:两组长度相同的旧编号,谁的 数学公式(保留原始 SVG) 小谁的字典序就小,后面接上同一个 数学公式(保留原始 SVG) 之后大小关系不变,所以每个状态只留 数学公式(保留原始 SVG) 最小的那组就够了。

最后从 数学公式(保留原始 SVG) 往下找第一个 数学公式(保留原始 SVG),它就是答案;把这个 数学公式(保留原始 SVG) 反复除以 数学公式(保留原始 SVG) 取余数,就拆回四个编号。数学公式(保留原始 SVG)数学公式(保留原始 SVG) 整行都是 数学公式(保留原始 SVG),与凑不出总价共用输出 数学公式(保留原始 SVG) 的分支,不必特判。

复杂度分析

时间复杂度:O(N log N + 4NV),V=10000。

空间复杂度:O(N+4V),包括礼物列表和状态表。

题解代码

import sys
input = sys.stdin.readline

def solve():
    n = int(input())
    gifts = sorted(tuple(map(int, input().split())) for _ in range(n))
    limit, base = 10000, 10001
    f = [[-1] * (limit + 1) for _ in range(5)]
    f[0][0] = 0
    for gift_id, price in gifts:
        for count in range(4, 0, -1):
            cur, prev = f[count], f[count - 1]
            for total in range(limit, price - 1, -1):
                old = prev[total - price]
                if old >= 0:
                    candidate = old * base + gift_id
                    if cur[total] < 0 or candidate < cur[total]:
                        cur[total] = candidate
    for total in range(limit, -1, -1):
        if f[4][total] >= 0:
            code = f[4][total]
            ids = []
            for _ in range(4):
                ids.append(code % base)
                code //= base
            print(*reversed(ids))
            return
    print(0)

solve()

正确性说明

按已处理礼物数归纳,f 保留每个件数、总价下最小编号编码。倒序件数确保当前礼物至多使用一次;追加相同且更大的编号不改变字典序关系,所以丢弃较大编码不会损失最优解。最终逆序枚举总价实现价格优先、编号次优。

易错点与边界

必须恰好四件而非至多四件,编号排序按整数而非字符串;倒序件数避免重复选同一礼物。Python 对象内存高于紧凑整数数组,不能照搬 Java 的字节数。

第 3 题:网络流量路径规划

题目描述

在大型数据通信网络中,网络管理员需要分析流量在网络设备之间的传输路径。给定一系列的网络链路配置,其中每条链路表示一个连接关系 数学公式(保留原始 SVG),表示数据包从源设备 数学公式(保留原始 SVG) 发送到目标设备 数学公式(保留原始 SVG)

请对该流量链路进行重新规划排序,所有这些链路都属于一个从核心交换机 Core-SW-01 开始的流量流,因此该路径必须从 Core-SW-01 开始。如果存在多种有效的流量路径,请按设备名称的字典排序返回最小的路径组合。

在网络运维和流量分析场景中,网络设备之间形成了一张复杂的拓扑图。当网络中出现异常流量或进行网络架构优化时,需要明确流量在设备之间的传输序列。本题模拟了根据预配置的链路信息,还原流量在网络中的实际传输路径的过程。

举例来说,若链路配置为 SW-A SW-B、Core-SW-01 SW-A、Router-X Router-Y、SW-B Router-X,则最终形成的流量路径依次为 Core-SW-01、SW-A、SW-B、Router-X、Router-Y,输出结果为 Core-SW-01 SW-A SW-B Router-X Router-Y。

在有多条可选链路时,优先选择目标设备名称字典序较小的链路进行跳转。题目保证所有链路至少构成一条从 Core-SW-01 开始的有效路径。

输入描述

若干行,每行两个由空格分隔的设备名称,表示一条链路的源设备和目标设备,行数记为 数学公式(保留原始 SVG)

设备名称由大写字母、数字、短横线组成,长度在 数学公式(保留原始 SVG)数学公式(保留原始 SVG) 个字符之间。

输出描述

一行,按流量传输顺序输出经过的设备名称,设备名称之间以空格分割。

样例1

输入

Core-SW-01 Switch-B
Core-SW-01 Switch-A
Switch-A Switch-B
Switch-A Core-SW-01
Switch-B Switch-A

输出

Core-SW-01 Switch-A Core-SW-01 Switch-B Switch-A Switch-B

样例解释

另一种有效的路径是 Core-SW-01、Switch-B、Switch-A、Core-SW-01、Switch-A、Switch-B,但是它的字典排序更大,应排在更靠后的位置。

题解:有向图欧拉路径(Hierholzer)

思路分析

把每条链路看成有向图的一条边,要求从 Core-SW-01 出发、每条链路恰好走一次,依次输出走过的设备;这样的走法可能不止一条,取字典序最小的那条。

每条边恰好走一次、一次把图走完的路线,图论里叫欧拉路径,也就是小时候玩的一笔画。所以这是一道有向图上的一笔画题,难点不在遍历本身,而在于”每步都挑名字最小的目标”这个直觉走法会中途走死,必须靠 Hierholzer 的后序压栈把走死的那一段挪到路径末尾。

算法实现

先看直觉走法为什么不够。三条链路 Core-SW-01 SW-A、Core-SW-01 SW-B、SW-B Core-SW-01,从 Core-SW-01 挑最小目标就是 SW-A,可 SW-A 没有出边,只用掉一条链路就停了;正确答案是 Core-SW-01 SW-B Core-SW-01 SW-A,得让 SW-A 留到最后走。

停下的位置并不是随机的。从起点任意往前走到走不动,停在的设备必然是欧拉路径的终点:中途经过的设备每进入一次就要离开一次,出入边成对消耗,只有终点进得去出不来。所以随手走出的这段一定是最终路径的一个后缀,剩下的链路构成若干条起终点相同的回路,各挂在这段路径的某个设备上,在挂点处展开插入即可。

Hierholzer 就是这个插入过程。维护一个显式栈,初始只有 Core-SW-01;栈顶还有未用出边时走目标名字典序最小的那条并压栈,走不动时把栈顶弹出、追加到结果尾部,链路用完后把结果逆序输出。

逆序是关键:先弹出的是先走死的设备,逆序后落到输出末尾,后来展开的回路自动补进前面的挂点。

出边按目标名降序排一次,取用时从末尾弹出即最小目标。比较必须用字符串字典序而非数字大小:SW-10 与 SW-9 逐字符比时 1 小于 9,SW-10 在前,按数字理解会走出另一条路径。

栈要显式写。链状拓扑下深度可达链路条数 数学公式(保留原始 SVG),递归实现在部分语言里会爆栈。

复杂度分析

时间复杂度数学公式(保留原始 SVG)。瓶颈是各设备出边的排序,总量为 数学公式(保留原始 SVG) 条边;Hierholzer 本身每条边只被取用一次、每个设备只被弹出一次,是 数学公式(保留原始 SVG)

空间复杂度数学公式(保留原始 SVG)。邻接表、显式栈与结果序列各最多存 数学公式(保留原始 SVG) 项。

题解代码

import sys
from collections import defaultdict
input = sys.stdin.readline

def solve():
    adj = defaultdict(list)
    for line in sys.stdin:
        parts = line.split()
        if parts:
            source, destination = parts
            adj[source].append(destination)
    for edges in adj.values():
        edges.sort(reverse=True)
    stack = ['Core-SW-01']
    order = []
    while stack:
        if adj[stack[-1]]:
            stack.append(adj[stack[-1]].pop())
        else:
            order.append(stack.pop())
    print(*reversed(order))

solve()

正确性说明

Hierholzer 在无剩余出边时才将顶点写入逆序结果,使提前抵达终点的分支留到最后。每条边仅弹出一次,拼接后形成使用全部边的路径;有序出边使能被插入当前位置的闭合子路优先使用较小目标,从而得到固定起点下的字典序最小欧拉路径。

易错点与边界

重复链路应作为独立边保留。题面名称字符说明与 Core-SW-01、Switch-A 样例的大小写不完全一致,按输入原字符串比较,不做大小写转换。

小结

优先从题面约束提炼模型,再用样例检查边界。本文保留题面数学符号的原始 SVG,代码统一为 Python 3;未给出的评测限制或规则不补作事实。