2021.9.8 华为笔试题第三题

复盘一下华为第三道笔试题,当时没时间了,马上就写完了,感觉每次在牛客做题都得调半天才能过
华为笔试最后一题基本都是出这种,当前任务依赖其他任务,拓扑排序这种题,或者是什么工序

题目描述

自己凭印象简单描述一下:
主要意思就是有一堆任务,然后任务之间有依赖关系,当前任务只有当前置任务完成以后,才能开始执行;每个任务有一个完成时间;
求出给定的一个目标任务最短的完成时间

思路

我的做法还是拓扑排序,先在一个哈希表中,键是任务编号,值是一个Set集合,里面存放的是这个任务所依赖的任务,也就是前置任务(可能需要存储二元组,加一个维度时间),也就是入度集合
可以将一个任务是哪些任务的前置任务,放到一个map里,方便后面查找,出度集合
因为输入都是字符串,module1,module2什么的,所以当时我是直接将里面的数字给分割出来然后用整数存储的,当时也意思到如果后面不是数字该怎么办,但是没时间了,就没考虑那么多
应该直接存储字符串就行了

处理好输入以后,然后定义一个结点Node类,里面两个属性,当前任务名称和时间

首先,先将没有前置任务的任务+时间,也就是Node,放到优先队列里,优先队列的排列顺序是按时间从小到大排序
每次弹出队首的任务top,说明这个任务在top.time时间完成了,然后找到这个任务top为前置任务的其他所有任务,将这个任务从他们的前置任务中删去,这里是复杂度的需要考量的地方,因为找当前任务为前置任务的其他任务,是O1的复杂度,遍历这些任务,删去当前任务,需要On(n为list中任务数目)的复杂度,我觉得这是最快的办法了
遍历list中任务删除的同时,将前置任务为空的任务,放入队列中,时间变成top.time加上当前任务的时间
直到弹出的任务是target,就说明target完成了,输出这个时间

想想对不对,应该没问题,因为在target开始的时候,必须是它前置任务都完成的时候,而前置任务同理,也是需要指定任务完成,而在每个任务入度为0的时候,就已经加入队列中了,所以其实任务的最早开始时间是固定的,所以最早完成时间也是固定的

重新写一下代码(输入输出就按印象中来了):
简单测试了一下,应该没问题

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String target = sc.nextLine();      //目标任务
        Map<String, Set<String>> rel = new HashMap<>();     //当前任务,当前任务的前置任务集合set,入度
        Map<String, List<String>> pre = new HashMap<>();    //前置任务,包含前置任务的任务集合list,出度
        Map<String, Integer> map = new HashMap<>();		//任务-时间
        List<String> nopre = new ArrayList<>();     //最开始没有前置任务的任务
        //int idx = 0;
        //while(idx++ < 4){        //测试
        while(sc.hasNextLine()){    //每一行表示当前任务,完成时间,前置任务(多个)
            String s = sc.nextLine();
            String[] ss = s.split(" ");
            String work = ss[0];    //当前任务
            int time = Integer.parseInt(ss[1]);     //完成时间
            map.put(work, time);
            Set<String> set = new HashSet<>();
            for(int i = 2; i < ss.length; i++){
                set.add(ss[i]);
                //取出前置任务的集合
                List<String> list = pre.getOrDefault(ss[i], new ArrayList<>());
                list.add(work);
                pre.put(ss[i], list);
            }
            //如果没有前置任务,放在nopre中
            if(set.isEmpty()){
                nopre.add(work);
            }else{
                rel.put(work, set);
            }
        }
        PriorityQueue<Node> pq = new PriorityQueue<>((a,b) -> (a.time - b.time));
        for(String s : nopre){
            pq.offer(new Node(s, map.get(s)));
        }
        while(!pq.isEmpty()){
            Node top = pq.poll();
            String work = top.work;
            int time = top.time;
            //如果是目标工作
            if(work.equals(target)){
                System.out.println(time);
                return;
            }
            //取出被当前工作所依赖的工作
            List<String> list = pre.getOrDefault(work, new ArrayList<>());
            //如果没有,跳过这个工作
            if(list.isEmpty()){
                continue;
            }
            for(String s : list){
                //删除这个工作
                Set<String> set = rel.get(s);
                set.remove(work);
                //如果set为空,加入队列,并且删除这个工作
                if(set.isEmpty()){
                    pq.offer(new Node(s, time + map.get(s)));
                    rel.remove(s);
                }else {
                    //如果不为空,还在rel里
                    rel.put(s, set);
                }
            }
        }
        //如果完不成这个任务就是-1
        System.out.println(-1);
    }
}

class Node{
    String work;
    int time;
    public Node(String work, int time){
        this.work = work;
        this.time = time;
    }
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值