【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试之【BFS】2023C-启动多任务排序【欧弟算法】全网注释最详细分类最全的华为OD真题题解

文章讲述了如何通过广度优先搜索(BFS)算法解决应用启动时任务依赖排序的问题,提供了Python、Java和C++三种语言的代码实现,用于处理任务之间的依赖关系,确保按正确顺序执行。
摘要由CSDN通过智能技术生成

题目描述与示例

题目描述

一个应用启动时,会有多个初始化任务需要执行,并且任务之间有依赖关系,例如A任务依赖B任务,那么必须在B任务执行完成之后,才能开始执行A任务。

现在给出多条任务依赖关系的规则,请输入任务的顺序执行序列,规则采用贪婪策略,即一个任务如果没有依赖的任务,则立刻开始执行,如果同时有多个任务要执行,则根据任务名称字母顺序排序。

例如:B任务依赖A任务,C任务依赖A任务,D任务依赖B任务和C任务,同时,D任务还依赖E任务。那么执行任务的顺序由先到后是:A任务,E任务,B任务,C任务,D任务。这里AE任务都是没有依赖的,立即执行

输入描述

输入参数每个元素都表示任意两个任务之间的依赖关系,输入参数中符号->表示依赖方向,例A->B表示A依赖B,多个依赖之间用单个空格分割

输出描述

输出为排序后的启动任务列表,多个任务之间用单个空格分割

示例一

输入

A->B C->B

输出

B A C

说明

任务AC都依赖于任务B。任务B执行后,AC立即执行,AC的执行顺序按照字典序排列。

示例二

输入

B->A C->A D->B D->C D->E

输出

A E B C D

解题思路

看到存在依赖关系,立马想到拓扑排序。

本题一个小难点在于如何对同级节点进行排序。

在BFS每一层搜索之前,可以构建一个空数组nodes_new,来储存搜索过程中新出现的入度为0的节点。这些新出现的这些节点属于拓扑排序中的同级节点,需要在for循环结束后进行排序,然后加入到ans中。

代码如下

while q:
    nodes_new = list()
    qSize = len(q)
    for _ in range(qSize):
        cur_node = q.popleft()
        for nxt_node in neighbor_dic[cur_node]:
            indegree_dic[nxt_node] -= 1
            if indegree_dic[nxt_node] == 0:
                nodes_new.append(nxt_node)
                q.append(nxt_node)
    nodes_new.sort()
    ans += nodes_new

代码

Python

# 题目:【BFS】2023C-启动多任务排序
# 分值:200
# 作者:闭着眼睛学数理化
# 算法:BFS/拓扑排序
# 代码看不懂的地方,请直接在群上提问


from collections import deque, defaultdict

# 对输入进行分割,得到若干个字符串,每一个字符串包含依赖关系
lst = input().split()
# 构建邻接表
neighbor_dic = defaultdict(list)

# 构建入度哈希表(因为节点名字是字符串而不是数字,因此用哈希表而不是数组)
indegree_dic = defaultdict(int)

# 遍历lst中的每一对依赖关系
for pairs in lst:
    # 根据"->"进行分割,得到节点a和b
    # "a->b"表示节点a依赖于节点b
    # 必须执行节点b之后,才能执行节点a
    a, b = pairs.split("->")
    # a为b的邻居,延长b的邻接节点
    neighbor_dic[b].append(a)
    # 节点a的入度增加
    indegree_dic[a] += 1

# 初始化答案数组,其中入度为0的节点为初始节点,同时根据字典序进行排序
ans = sorted(k for k in neighbor_dic.keys() if indegree_dic[k] == 0)
# 初始化队列,其中队中元素为ans中的元素
q = deque(ans)

# BFS
while q:
    # 初始化一个列表,储存新出现的入度为0的节点
    # 新出现的这些节点,需要在for循环结束后立即执行,加入到ans中
    nodes_new = list()
    # 获得当前层的节点数
    qSize = len(q)
    # 循环qSize次,弹出队列中所有节点
    for _ in range(qSize):
        # 弹出当前队头节点cur_node
        cur_node = q.popleft()
        # 考虑cur_node的所有近邻节点nxt_node
        for nxt_node in neighbor_dic[cur_node]:
            # 近邻nxt_node的入度-1
            indegree_dic[nxt_node] -= 1
            # 如果该近邻节点的入度降为0
            if indegree_dic[nxt_node] == 0:
                # 将其加入nodes_new数组中
                nodes_new.append(nxt_node)
                # 将其加入q中
                q.append(nxt_node)
    # 对nodes_new根据字典序进行排序,然后加在ans后面
    # 表示需要立即执行nodes_new中的节点
    nodes_new.sort()
    ans += nodes_new

print(*ans)

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        String[] lst = input.split(" ");
        Map<String, List<String>> neighborDic = new HashMap<>();
        Map<String, Integer> indegreeDic = new HashMap<>();

        for (String pairs : lst) {
            int pos = pairs.indexOf("->");
            String a = pairs.substring(0, pos);
            String b = pairs.substring(pos + 2);

            neighborDic.computeIfAbsent(b, k -> new ArrayList<>()).add(a);
            indegreeDic.put(a, indegreeDic.getOrDefault(a, 0) + 1);
        }

        List<String> ans = new ArrayList<>();

        for (String node : neighborDic.keySet()) {
            if (!indegreeDic.containsKey(node)) {
                ans.add(node);
            }
        }

        Collections.sort(ans);
        Queue<String> q = new LinkedList<>(ans);

        while (!q.isEmpty()) {
            List<String> nodesNew = new ArrayList<>();
            int qSize = q.size();

            for (int i = 0; i < qSize; i++) {
                String curNode = q.poll();

                if (neighborDic.containsKey(curNode)) {
                    for (String nxtNode : neighborDic.get(curNode)) {
                        indegreeDic.put(nxtNode, indegreeDic.get(nxtNode) - 1);
                        if (indegreeDic.get(nxtNode) == 0) {
                            nodesNew.add(nxtNode);
                            q.add(nxtNode);
                        }
                    }
                }
            }

            Collections.sort(nodesNew);
            ans.addAll(nodesNew);
        }

        for (String node : ans) {
            System.out.print(node + " ");
        }
    }
}

C++

#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <algorithm>

using namespace std;

int main() {
    string input;
    getline(cin, input);
    vector<string> lst;
    string temp;
    for (char i : input) {
        if (i == ' ') {
            lst.push_back(temp);
            temp = "";
        } else {
            temp += i;
        }
    }
    lst.push_back(temp);

    unordered_map<string, vector<string>> neighborDic;
    unordered_map<string, int> indegreeDic;

    for (string pairs : lst) {
        string delimiter = "->";
        size_t pos = pairs.find(delimiter);
        string a = pairs.substr(0, pos);
        string b = pairs.substr(pos + delimiter.length());

        neighborDic[b].push_back(a);
        indegreeDic[a]++;
    }

    vector<string> ans;

    for (auto node : neighborDic) {
        if (indegreeDic.find(node.first) == indegreeDic.end()) {
            ans.push_back(node.first);
        }
    }
    
    sort(ans.begin(), ans.end());
    queue<string> q;
    for (string node : ans) {
        q.push(node);
    }

    while (!q.empty()) {
        vector<string> nodesNew;
        int qSize = q.size();

        for (int i = 0; i < qSize; i++) {
            string curNode = q.front();
            q.pop();

            if (neighborDic.find(curNode) != neighborDic.end()) {
                for (string nxtNode : neighborDic[curNode]) {
                    indegreeDic[nxtNode]--;
                    if (indegreeDic[nxtNode] == 0) {
                        nodesNew.push_back(nxtNode);
                        q.push(nxtNode);
                    }
                }
            }
        }
        sort(nodesNew.begin(), nodesNew.end());
        ans.insert(ans.end(), nodesNew.begin(), nodesNew.end());
    }

    for (string node : ans) {
        cout << node << " ";
    }

    return 0;
}

时空复杂度

时间复杂度:O(N)

空间复杂度:O(N)


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

  • 25
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值