华为开发岗暑期实习笔试(2025年4月16日)

刷题小记:

第一题怀疑测试样例不完整,贪心法不应该能够解决该题。第二题使用0-1BFS解决单源最短路径的问题,往往搭配双端队列实现。第三题是运用动态规划解决最大不重叠子区间个数的问题,难点在于满足3重判断规则,所需数据结构及相关操作较多。

1.最小测试用例集覆盖

题目分析:

题目描述:

二维cases表示测试用例的覆盖情况,cases[i][j]为 1 表示第i个测试用例覆盖了第j个模块,为 0 则表示未覆盖。

求一个最小的测试用例集合,使得该集合能够覆盖所有模块。

返回该最小的集合大小,如果不存在这样的集合,返回-1。

输入描述:

第一行给定两个整数,分别表示用例总数n和代码模块总数m

第二行开始的n行,每行有m个整数(0或1),表示覆盖情况。

n,m均属于[1,50]区间

输出描述:

输出一个整数表示最小用例集合的大小,若不存在则输出-1

解题思路:

当且仅当 存在j,对任意的i,均有cases[i][j] == 0时,不存在最小覆盖集合,此时返回-1。

第i行表示第i个测试用例对m个模块的覆盖情况,

用一个长度为m的数组mo记录样例集合对模块的覆盖情况,其值为每一列由各样例的对应列取并得到。

如果采用回溯法(暴力搜索),那么遍历全部覆盖集的时间复杂度为O(2^n),而检查数组mo的时间复杂度为O(n),那么总的时间复杂度为O(n * 2^n),太大!

如果采用贪心法,每次选择覆盖模块最多的测试样例添入集合,仍然无法保证测试样例集合最小。(据说真实考试情况下,该贪心法过了?!)

2.小慕的地铁大挑战

题目分析:

题目描述:

有N条地铁线路,每条线路按顺序连接若干站点,且一条线路上不存在重复的站点名。

地铁乘坐规则如下:进入任意一条地铁线路需支付2元,每换乘一次加收1元。

现求小慕从某个出发站前往指定的目的站,规划一条最省钱的路线并返回最低票价;若不能抵达,输出"NA"。

输入描述:

第一行一个整数N表示地铁线路数量,介于[1,1000]。

接下来N行,每行描述一条地铁线路,用空格分隔若干个站点名(站点名长度不超过100个字符),最多包含100个站点。不同线路间站点名可能重复,表示是换乘站。

第N+1行包含两个站点名,分别是出发站和目的站。

输入保证:若存在可达路径,则方案唯一。

输出描述:

第一行输出“换乘路径”(除起始点外,只包含可能存在的换乘站点),站点之间用"-"连接。

第二行输出该方案的总票价。

若无可达路径,只输出一行"NA"

解题思路:

运用0-1广度优先搜索遍历所有路径,找出权值最小的路径,其中:在线路内部移动的边权为0,换乘时的边权为1。

关键步骤:
  1. 构建状态图:key是(站点名,所属线路编号),value是(下一站点,权重)的列表,其中用"虚拟线路编号-1"表示换乘口
    1. 对于同一条地铁线路的相邻站点(A,i)和(B,i)相连,即给(A,i)的value列表添加((B,i),0),给(B,i)的value列表添加((A,i),0)
    2. 对于每个站点,将其与对应的虚拟换乘口相连
      1. 从站点(A,i)到虚拟换乘口(A,-1)的权为1,即给(A,i)的value列表添加((A,-1),1)
      2. 从虚拟换乘口(A,-1)到站点(A,i)的权为0,即给(A,-1)的value列表添加((A,i),0)
  1. 路径搜索算法 0-1BFS:
    1. 使用双端队列Deque,优先处理权值为0的边,即将其加入队头(优先出队);处理权值为1的边时,将其加入队尾(后出队),已访问过的节点直接跳过
    2. 用一个映射d记录每个节点的最小费用,初始化为INT_MAX
    3. 用一个映射pre记录每个节点的前置节点,以便第一次找到终点后复现路径(权值为0的节点被优先处理,广度优先搜索能确保找到目标点时路径代价最小)
  1. 路径还原与票价计算:
    1. 找到终点时,借助pre映射还原路径,每遇到(node, -1)的节点表示为换乘节点,将其添加入路径并记录换乘代价
    2. 票价 = 2 + 换乘代价 - 1,因为(起点, -1)被视作了换乘节点加入路径,而其本身是不需要换乘的,只是为了统一写法才记为-1,因此票价公式末尾减去1
  1. 如果最终最短路径映射d不包含终点,表示不存在能够从起点到达该终点的路径,输出NA。

3.满足尽可能多的业务需求的IP区间方案组

题目分析:

题目描述:

业务的网络地址需求用一个闭区间[startip, endip]表示。

由于要求不同业务的IP地址区间不能重叠,要求按照一定的顺序将这些业务需求排序,尽可能满足更多的业务需求:

  • 当业务数量相同时,以IP地址占用区间最少的优先
  • 当业务数量相同时且IP地址占用区间大小也相同时,按照IP范围排序,比较起始地址,起始地址最小者优先。
输入描述:

第一行为业务个数N,有效范围是[1, 1000]

接下来N行是IP地址区间,每行有startip和endip,均为合法的IPv4地址格式,即(A, B, C, D),其中ABCD的取值范围是[0, 255]

注意:IP地址大小的比较,是按照A、B、C和D的顺序进行比较。

输出描述:

输出排序好的M个IP区间,每行一个。

解题思路:

首先将IP地址转换成32位的整数进行存储,便于比较大小。

然后将这些IP区间按照startip进行升序排序,若startip相同,那么按照endip进行升序排序,得到32位转换以及排序后的N行2列的整型数组ips。

动规五部曲:
  1. 确定dp数组以及下标的含义:dp[i]表示以第i个区间结尾的最大不重叠子区间数量
  2. 确定递推公式:对于以j(j < i)为结尾的最大不重叠子区间方案,如果与第i个区间不重叠,那么:
    1. 如果dp[j] + 1> dp[i],那么以第i个区间为结尾的方案为在以第j个区间为结尾的最大不重叠区间数方案的基础上加上第i个区间;
    2. 如果dp[j] + 1 == dp[i],那么比较以第i个区间为结尾的最优方案,以及以第j个区间为结尾的最优方案的基础上添加第i个区间,比较这两个方案的长度,选择较短者;如果两个方案的长度相同,比较两个方案的起始IP地址。
  1. 确定遍历方向:由于dp[i]依赖于dp[j](j < i),因此正序遍历即可。
  2. dp数组初始化:遍历第i个区间时,由于一定以第i个区间结尾,因此初始化dp[i] = 1表示将第i个区间添入业务组合方案。
import java.util.*;

public class Ipv4ToIntConverter {
    public static int ipv4ToInt(String ipAddress) {
        String[] parts = ipAddress.split("\\.");
        int result = 0;
        for (int i = 0; i < 4; i++) {
            int octet = Integer.parseInt(parts[i]);
            result = (result << 8) | octet;
        }
        return result;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        scanner.nextLine(); // 消耗掉换行符

        int[][] ips = new int[n][2];
        for (int i = 0; i < n; i++) {
            String[] line = scanner.nextLine().split(" ");
            ips[i][0] = ipv4ToInt(line[0]);
            ips[i][1] = ipv4ToInt(line[1]);
        }

        // 按照 startip 升序排序,如果 startip 相同,按照 endip 升序排序
        Arrays.sort(ips, (a, b) -> {
            if (a[0] == b[0]) {
                return Integer.compare(a[1], b[1]);
            }
            return Integer.compare(a[0], b[0]);
        });

        // dp[i] 表示以第 i 个区间结尾的最大不重叠区间数量
        int[] dp = new int[n];
        // 记录每个状态下选择的区间
        List<List<int[]>> choices = new ArrayList<>();
        // 记录每个状态下选择的区间的总长度
        int[] lengths = new int[n];

        for (int i = 0; i < n; i++) {
            dp[i] = 1;
            choices.add(new ArrayList<>());
            choices.get(i).add(ips[i]);
            lengths[i] = ips[i][1] - ips[i][0];
            for (int j = 0; j < i; j++) {
                if (ips[j][1] < ips[i][0]) {// 第i个区间与第j个区间不重合
                    if (dp[j] + 1 > dp[i]) {
                        dp[i] = dp[j] + 1;
                        List<int[]> newChoice = new ArrayList<>(choices.get(j));
                        newChoice.add(ips[i]);
                        choices.set(i, newChoice);
                        lengths[i] = lengths[j] + (ips[i][1] - ips[i][0]);
                    } else if (dp[j] + 1 == dp[i]) {
                        int newLength = lengths[j] + (ips[i][1] - ips[i][0]);
                        if (newLength < lengths[i]) {
                            List<int[]> newChoice = new ArrayList<>(choices.get(j));
                            newChoice.add(ips[i]);
                            choices.set(i, newChoice);
                            lengths[i] = newLength;
                        } else if (newLength == lengths[i]) {
                            if (newChoice.get(0)[0] < choices.get(i).get(0)[0]) {
                                List<int[]> newChoice = new ArrayList<>(choices.get(j));
                                newChoice.add(ips[i]);
                                choices.set(i, newChoice);
                            }
                        }
                    }
                }
            }
        }

        // 找到最大不重叠区间数量的方案
        int maxCount = 0;
        List<int[]> bestChoice = new ArrayList<>();
        int minLength = Integer.MAX_VALUE;
        int startIp = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            if (dp[i] > maxCount) {
                maxCount = dp[i];
                bestChoice = choices.get(i);
                minLength = lengths[i];
                startIp = bestChoice.get(0)[0];
            } else if (dp[i] == maxCount) {
                if (lengths[i] < minLength) {
                    bestChoice = choices.get(i);
                    minLength = lengths[i];
                    startIp = bestChoice.get(0)[0];
                } else if (lengths[i] == minLength) {
                    if (choices.get(i).get(0)[0] < startIp) {
                        bestChoice = choices.get(i);
                        startIp = bestChoice.get(0)[0];
                    }
                }
            }
        }

        // 输出结果
        for (int[] ip : bestChoice) {
            System.out.println(intToIpv4(ip[0]) + " " + intToIpv4(ip[1]));
        }

        scanner.close();
    }

    public static String intToIpv4(int ip) {
        StringBuilder sb = new StringBuilder();
        for (int i = 3; i >= 0; i--) {
            sb.append((ip >> (i * 8)) & 255);
            if (i > 0) {
                sb.append(".");
            }
        }
        return sb.toString();
    }
}
<think>好的,我现在需要帮用户寻找与暑期实习相关的技术岗位机会,特别是开发和运维方向。首先,用户的问题比较明确,但可能需要更具体的指导,比如如何找到这些机会,哪些平台有效,以及申请时的注意事项。 我应该先考虑用户可能的意图。他们可能是大学生或者刚毕业的学生,想要在暑期积累相关工作经验。开发和运维属于技术岗位,竞争可能比较激烈,所以用户可能需要知道如何高效地搜索和申请。 接下来,我需要调用网络搜索工具,查找可靠的招聘平台,比如实习僧、BOSS直聘、拉勾网,这些平台专门针对实习和技术岗位。另外,大厂的官网和校招页面也很重要,像腾讯、阿里、华为这些公司通常有暑期实习项目。还要考虑内推渠道,比如知乎、牛客网,或者通过学长学姐推荐,这可能提高成功率。 另外,用户可能需要了解申请流程和时间节点。暑期实习通常有固定的申请时间,比如提前批可能在3-4月,正式批在5-6月,需要提醒用户注意截止期。同时,技术岗位的简历应该突出项目经验和技能,比如熟悉Git、掌握Python/Java,这些是加分项。 在整合信息时,要分步骤给出方法,比如分平台推荐、公司官网、内推渠道、简历优化等。每个方法下要具体说明如何操作,比如在BOSS直聘上使用筛选功能,或者在校招页面关注动态。同时要避免使用第一人称和步骤词汇,保持客观。 可能还需要提醒用户准备笔试和面试,比如刷LeetCode,复习操作系统和网络知识。运维岗位可能需要了解Linux和Shell脚本,这些要特别指出。 最后,生成相关问题时要基于用户的需求,比如如何写技术简历,暑期实习申请时间,或者开发和运维岗位的具体要求。确保问题相关且有帮助。</think>以下是针对技术岗位(开发/运维)暑期实习机会的检索结果整合及实用建议: **1. 主流招聘平台筛选** - 实习僧、BOSS直聘、拉勾网设置「技术实习」+「在校生」筛选条件 - 搜索关键词组合示例:$暑期实习+Java开发$ / $运维实习生+Shell脚本$ - 开发岗重点关注GitHub活跃项目经验,运维岗突出Linux系统管理能力 **2. 企业官方渠道监测** 访问目标公司校招官网(示例代码获取腾讯招聘页面): ```python import requests url = "https://careers.tencent.com/students.html" response = requests.get(url) # 解析页面中的「暑期实习」板块 ``` 大厂招聘时间公式:$$T_{apply} = T_{official} - 30 \text{天}$$(建议官方截止前30天投递) **3. 技术社区资源挖掘** - GitHub「实习」话题下查看最新项目:`is:issue label:"internship"` - 牛客网刷题时关注关联企业题库,如$N_{leetcode}=200+$可尝试字节跳动提前批 - Stack Overflow Careers设置「Internship」过滤条件 **4. 运维岗专项准备** 需掌握技术栈示例: ```bash # 监控系统搭建示例 #!/bin/bash nagios_cfg="/etc/nagios3/nagios.cfg" grep "check_disk" $nagios_cfg || echo "未配置磁盘监控" ``` **5. 申请流程优化** - 建立投递跟踪矩阵:$M_{apply}=[企业,岗位,进度,联系方式]$ - 笔试准备公式:$$P_{pass} = 0.7A_{algorithm} + 0.3S_{system}$$(算法题70%+系统设计30%)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值