Lintcode -616. 安排课程

描述

你需要去上n门九章的课才能获得offer,这些课被标号为 0 到 n-1 。
有一些课程需要“前置课程”,比如如果你要上课程0,你需要先学课程1,我们用一个匹配来表示他们: [0,1]

给你课程的总数量和一些前置课程的需求,返回你为了学完所有课程所安排的学习顺序。

可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

您在真实的面试中是否遇到过这个题?  是

题目纠错

样例

给定 n = 2, prerequisites = [[1,0]]
返回 [0,1]

给定 n = 4, prerequisites = [1,0],[2,0],[3,1],[3,2]]
返回 [0,1,2,3] or [0,2,1,3]

源代码如下:

class Solution {
public:
    /*
     * @param numCourses: a total of n courses
     * @param prerequisites: a list of prerequisite pairs
     * @return: the course order
     */
struct Edge{        //边结点的定义
    int dest;                                //边的另一顶点位置
    Edge *link;                                //下一条边链指针
    Edge() {}                                        //构造函数
    Edge(int num){                        //构造函数    
        dest = num;
        link = NULL;
    }
    bool operator != (Edge &R)const{            //判边不等否。#只能用于同一行的单链表中
        return (dest != R.dest);
    }    
};

//顶点的定义
struct Vertex{
    int data;                    //顶点的名字
    Edge *adj;            //边链表的头指针
};
int numVertices=0;
int numEdges=0;
Vertex *NodeTable;        //创建顶点表数组
int NumberOfVertices(){                //返回当前顶点数    
        return numVertices;
    }
int getValue(int i){    //返回该邻接顶点的编号,若不存在则返回0        //取位置为i的顶点中的值    
        return (i >= 0 && i < NumberOfVertices()) ? NodeTable[i].data : 0;
    }
     
int getFirstNeighbor(int v){
    if (v != -1){                                    //顶点v存在    
        Edge *p = NodeTable[v].adj;            //对应边链表第一个边结点
        if (p != NULL){                                //存在, 返回第一个邻接顶点        
            return p->dest;
        }
    }
    return -1;                                        //第一个邻接顶点不存在
}
int getNextNeighbor(int v, int w){
    if (v != -1){                                    //顶点v存在    
        Edge *p = NodeTable[v].adj;            //对应边链表第一个边结点
        while (p != NULL && p->dest != w){            //寻找邻接顶点w        
            p = p->link;
        }
        if (p != NULL && p->link != NULL){
            return p->link->dest;                     //返回下一个邻接顶点
        }
    }
    return -1;                                         //下一邻接顶点不存在
}
bool insertEdge(int v1, int v2){
//     if (v1 >= 0 && v1 < numVertices && v2 >= 0 && v2 < numVertices){
         Edge *q, *p = NodeTable[v1].adj;        //v1对应的边链表头指针
        while (p != NULL && p->dest != v2){         //寻找邻接顶点v2        
            p = p->link;
        }
        if (p != NULL){                //找到此边, 不插入        
            return false;
        }
        p = new Edge;            //否则, 创建新结点
        q = new Edge;
        p->dest = v2;
        p->link = NodeTable[v1].adj;                 //链入v1边链表
        NodeTable[v1].adj = p;
        numEdges++;
        return true;
//     }
//     return false;
}
void insertVertex(const int& vertex){
    //在图的顶点表中插入一个新顶点vertex。若插入成功,函数返回true, 否则返回false。
    NodeTable[numVertices].data = vertex;            //插入在表的最后
    numVertices++;
}

void fun(int numCourses) {
        NodeTable = new Vertex[numCourses];
        for (int i = 0; i < numCourses; i++) {
            NodeTable[i].adj = NULL;
        }
    }
    
    vector<int> findOrder(int numCourses, vector<pair<int, int>> &prerequisites) {
        // write your code here
        int numpre = prerequisites.size();
        fun(numCourses);
        for(int i=0;i<numCourses;i++){//插入顶点
            insertVertex(i);
        }
        int i, j, w, v;
        int top = -1;                //入度为零顶点的栈初始化
        int n = numCourses;    //网络中顶点个数
        numVertices = numCourses;
        int *count = new int[n];  //入度数组兼入度为零顶点栈
        for (i = 0; i < n; i++) count[i] = 0;
        for (int p = 0; p < numpre; p++) {
            i = prerequisites[p].first;
            j = prerequisites[p].second;
            if (i > -1 && i < n && j > -1 && j < n) {
                if(insertEdge(i, j)){  
                    count[j]++;
                }
                cout<<j<<count[j];
            }
        }
        for (i = 0; i < n; i++)          //检查网络所有顶点
            if (count[i] == 0)            //入度为零的顶点进栈
            {
                count[i] = top;  top = i;
            }
        int num = 0;
        vector<int>result(n);
        for (i = 0; i < n; i++){          //期望输出n个顶点
            if (top == -1) {               //中途栈空,转出
                cout << "网络中有回路!" << endl;
                return vector<int>();
            }

            else {                                        //继续拓扑排序
                v = top;  top = count[top];      //退栈v            
                //cout << getValue(v);   //输出
                result[num++] = getValue(v);
                w = getFirstNeighbor(v);
                while (w != -1) {         //扫描顶点v的出边表
                    count[w]--;          //邻接顶点入度减一
                    if (!count[w])               //入度减至零,进栈
                    {
                        count[w] = top;  top = w;
                    }
                    w = getNextNeighbor(v, w);
                }     //一个顶点输出后,调整其邻接顶点入度
            }      //输出一个顶点,继续for循环
        }
        vector<int>finresult(num);
        for(int fin=0;fin<num;fin++){
            finresult[fin]=result[num-fin-1];
        }
        return finresult;
    }
};

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值