LeetCode刷题记168-1203. 项目管理

8 篇文章 0 订阅
3 篇文章 0 订阅

LeetCode刷题记168

1203. 项目管理

题目
在这里插入图片描述

class Solution {
    public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
        int k = m;
        for (int i = 0; i < n; i ++) {
            if(group[i] == -1) group[i] = k ++;  // 给没有分类的组赋予一个新的组别号
        }
        List<Integer>[] itemsOfGroup = new ArrayList[k];  // 记录每个组的任务
        for (int i = 0; i < k; i ++) {
            itemsOfGroup[i] = new ArrayList<Integer>();
        }
        for (int i = 0; i < n; i ++) {
            itemsOfGroup[group[i]].add(i);
        }
        
        Set<Integer>[] afterGroups = new HashSet[k];  // 记录每个组的后置组
        Set<Integer>[] afterItems = new HashSet[n];  // 记录每个任务的组内后置任务
        for (int i = 0; i < k; i ++) {
            afterGroups[i] = new HashSet<Integer>();
        }
        for (int i = 0; i < n; i ++) {
            afterItems[i] = new HashSet<Integer>();
        }
        for (int i = 0; i < n; i ++) {
            int curGroupId = group[i];  // 当前组的组别名
            for (Integer id : beforeItems.get(i)) {
                int befGroupId = group[id];  // 前置组别名
                if (befGroupId == curGroupId) {  // 同组内的前置
                    afterItems[id].add(i);
                } else {  // 添加到后置组中
                    afterGroups[befGroupId].add(curGroupId);  
                }
            }
        }
        int[] beforeGroupsNum = new int[k];  // 前置组的数量
        for (int i = 0; i < k; i ++) {
            for (Integer id : afterGroups[i]) {
                beforeGroupsNum[id] ++;
            }
        }
        int[] beforeItemsNum = new int[n];  // 同组内前置的任务数量 
        for (int i = 0; i < n; i ++) {
            for (Integer id : afterItems[i]) {
                beforeItemsNum[id] ++;
            }
        }
        int[] ans = new int[n];
        int ansId = 0;
        // 外层对组间进行拓扑排序
        Queue<Integer> queueGroup = new LinkedList<Integer>();
        for (int i = 0; i < k; i ++) {
            if (beforeGroupsNum[i] == 0) {
                queueGroup.add(i);
            }
        }
        while (!queueGroup.isEmpty()) {
            int curGroupId = queueGroup.poll();
            // 对组内进行拓扑排序
            Queue<Integer> queueItem = new LinkedList<Integer>();
            for (Integer id : itemsOfGroup[curGroupId]) {
                if (beforeItemsNum[id] == 0) {
                    queueItem.add(id);
                }
            }
            int itemNum = 0;
            while (!queueItem.isEmpty()) {
                int curItemId = queueItem.poll();
                itemNum ++;
                ans[ansId ++] = curItemId;
                for (Integer id : afterItems[curItemId]) {
                    beforeItemsNum[id] --;
                    if (beforeItemsNum[id] == 0) {
                        queueItem.add(id);
                    }
                }
            }
            if (itemNum != itemsOfGroup[curGroupId].size()) {
                return new int[]{};  // 组内拓扑排序不满足
            }
            for (Integer id : afterGroups[curGroupId]) {
                beforeGroupsNum[id] --;
                if (beforeGroupsNum[id] == 0) {
                    queueGroup.add(id);
                }
            }
        }
        if (ansId != n) return new int[]{};  // 组间拓扑排序不满足
        return ans;
    }
}

两层拓扑,这个题目我竟然一发就过了,好嗨心~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值