leetcode 图

997. 找到小镇的法官

法官是出度为0,入度为n-1的结点,且是唯一一个

class Solution {
public:
    int findJudge(int N, vector<vector<int>>& trust) {
        // 法官是出度为0,入度为n-1的结点,且是唯一一个
        vector<int> inDegree(N+1, 0);
        vector<int> outDegree(N+1, 0);

        for(int i = 0; i < trust.size(); i++){
            int start = trust[i][0];
            int end = trust[i][1];

            inDegree[end]++;
            outDegree[start]++;
        }

        for(int i = 1; i <= N; i++){ 
            if(outDegree[i] == 0 && inDegree[i] == N-1){
                return i;
            }
        }
        return -1;
    }
};

1042. 不邻接植花

邻接表,初始化,然后默认染色为0, 依次删除邻接表中的颜色即可

class Solution {
public:
    vector<int> gardenNoAdj(int N, vector<vector<int>>& paths) {

        // 建立邻接表
        vector<int> G[N]; 
        for(int i = 0; i < paths.size(); i++){
            G[paths[i][0]-1].push_back(paths[i][1]-1);
            G[paths[i][1]-1].push_back(paths[i][0]-1);
        }
        vector<int> ans(N, 0); // 默认所有花园不染色,染0

        for(int i = 0; i < N; i++){
            set<int> color{1, 2, 3, 4}; // 从第一个花园开始走,把与它邻接的花园的颜色从color{1,2,3,4}这个颜色集中删除;
            for(int j = 0; j < G[i].size();j++){ // 遍历邻接表,去除染过色的颜色
                color.erase(ans[G[i][j]]); // 把已染过色的去除
            }
            ans[i] = *(color.begin()); // 染色,删完了所有与它相邻的颜色,就可以把集合中剩下的颜色随机选一个给它了,为了简单,将集合中的第一个颜色赋给当前花园;
        }
        return ans;
    }
};

133. 克隆图

DFS

class Solution {
public:
    Node* cloneGraph(Node* node) {
        // DFS
        if(node == NULL){
            return NULL;
        }
        unordered_map<Node*, Node*> visited;
        Node* node_clone = dfs(node, visited);
        return node_clone;
    }

    Node* dfs(Node* node, unordered_map<Node*, Node*>& visited){
        if(visited.find(node) != visited.end()){
            // 找到节点,已经访问过了
            return visited[node];
        }
        Node* node_clone = new Node(node->val); // 复制当前节点
        visited[node] = node_clone; // 该节点已经被访问过了

        for(int i = 0; i < node->neighbors.size(); i++){
            // 访问邻居
            Node* node_neighbour_clone = dfs(node->neighbors[i], visited); // 访问所有相邻的节点
            node_clone->neighbors.push_back(node_neighbour_clone); // 将结果存入邻居中
        }
        return node_clone;
    }
};

BFS

class Solution {
public:
    Node* cloneGraph(Node* node) {
        // BFS
        if(node == NULL){
            return NULL;
        }
        unordered_map<Node*, Node*> mmap; // 记录是否被访问过

        Node* head = new Node(node->val);
        mmap[node] = head;

        queue<Node*> q;
        q.push(node);

        while(!q.empty()){
            Node* temp = q.front(); // 取队列首节点
            q.pop(); // 出队列

            for(auto neighbor_node : temp->neighbors){ // 遍历邻居节点
                if(mmap.find(neighbor_node) == mmap.end()){
                    // mmap中不存在,没有被访问过
                    mmap[neighbor_node] = new Node(neighbor_node->val); // 将该节点放入mmap中
                    q.push(neighbor_node);  // 放入队列
                    mmap[temp]->neighbors.push_back(mmap[neighbor_node]);  // 放入temp节点的邻居中
            }
        }
        return head;
    }

};

面试题 04.01. 节点间通路

BFS

class Solution {
public:
    bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
        // BFS
        vector<bool> visited(n);
        visited[start] = true; // 初始化 访问过起点

        vector<vector<int>> map(n);

        // 初始化邻接表
        for(int i = 0; i < graph.size(); i++){
            map[graph[i][0]].push_back(graph[i][1]);
        }  

        // 队列
        queue<int> q;
        q.push(start);

        while(!q.empty()){
            int temp = q.front();
            q.pop();

            if(temp == target){
                // 到达终点了
                return true;
            }

            for(int i = 0; i < map[temp].size(); i++){
                if(!visited[map[temp][i]]){
                    // 尚未访问过 放入队列
                    q.push(map[temp][i]);
                    visited[map[temp][i]] = true; // 标记访问过
                }
            }
        }
        return false;
    }
};

DFS

class Solution {
public:
    bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
        // DFS
        vector<int> visited(n, false);
        vector<vector<int>> map(n);

        // 邻接表初始化
        for(int i = 0; i < graph.size(); i++){
            map[graph[i][0]].push_back(graph[i][1]);
        }

        bool found = false;
        dfs(map, start, target, found, visited);
        return found;
    }

    void dfs(vector<vector<int>>& map, int start, int target, bool& found, vector<int>& visited){
        if(found){
            return;
        }
        if(start == target){
            found = true;
        }
        for(int i = 0; i < map[start].size(); i++){
            if(!visited[map[start][i]]){
                // 未被访问过
                visited[map[start][i]] = true;
                dfs(map, map[start][i], target, found, visited);
                visited[map[start][i]] = false;
            }
        }
    }
};

785. 判断二分图

染色法,DFS

class Solution {
public:
    bool isBipartite(vector<vector<int>>& graph) {
        int size = graph.size();
        if(size == 0){
            return false;
        }
        // 染色数组,每个顶点的染色情况:0 表示未被染色, 1表示染成黑色 2表示染成白色。
        vector<int> color(size, 0);
        for(int i = 0; i < size; i++){
            if(!dfs(graph, color, i, 0)){
                return false;
            }
        }
        return true;
    }
// 先找到一个没被染色的节点u,把它染上一种颜色,之后遍历所有与它相连的节点v,如果节点v已被染色并且颜色和节点u一样,那么就不是二分图。
// 如果这个节点v没有被染色,先把它染成与节点u不同颜色的颜色,然后遍历所有与节点v相连的节点...如此递归下去。
    bool dfs(vector<vector<int>>& graph, vector<int>& color, int i, int lastColor){
        if(color[i] != 0){
            // 已经被染色了
            return color[i] != lastColor; // 必须要和之前节点颜色,相同颜色和节点u一样就不是二分图
        }
        // 未被染色时,染色 若lastColor为1 就染2
        color[i] = ( (lastColor == 1) ? 2 : 1);

        for(int j = 0; j < graph[i].size(); j++){
            if(!dfs(graph, color, graph[i][j], color[i])){
                return false;
            }
        }
        return true;
    }

};

BFS

class Solution {
public:
    bool isBipartite(vector<vector<int>>& graph) {
        int size = graph.size();
        if(size == 0){
            return false;
        }
        // 染色数组,每个顶点的染色情况:0 表示未被染色, 1表示染成黑色 2表示染成白色。
        vector<int> color(size, 0);
        for(int i = 0; i < size; i++){
            if(color[i] == 0){
                if(!bfs(graph, color, i)){
                    return false;
                }
            }
        }
        return true;
    }

    bool bfs(vector<vector<int>>& graph, vector<int>& color, int i){
       queue<int> q;
       q.push(i);
       int lastColor = 0;

       while(!q.empty()){
            int temp = q.front();
            q.pop();
            lastColor = color[temp];
            
            for(int j = 0; j < graph[temp].size(); j++){// 邻接节点
                // 如果未被染色 放入queue
                // 注意这里要用graph获取邻接节点(我脑子抽了直接用j。。。)
                int v = graph[temp][j];
                if(color[v] == 0){
                    q.push(v);
                    // 染色, 与上一次节点的color不一致
                    color[v] = (lastColor == 1) ? 2 : 1; 
                }else if(color[v] == lastColor){
                    // 已经被染色了,且染的颜色和顶点相同的
                    return false;
                }
            }
        }
        return true;
    }

};

399. 除法求值

双百分,有向图求两点间是否存在路径,DFS

class Solution {
public:
    // 邻接图
    unordered_map<string, vector<pair<string, double>>> m; 
    // 答案
    vector<double> ans;

    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {

        // 初始化邻接图
        for(int i = 0; i < equations.size(); i++){
            m[equations[i][0]].push_back(pair<string, double>(equations[i][1], values[i]));
            m[equations[i][1]].push_back(pair<string, double>(equations[i][0], 1/values[i]));
        }
        // 遍历
        for(auto x: queries){
            if(x[0] == x[1]){
                // 除数和被除数一样
                if(m.find(x[0]) != m.end()){
                    // 数是存在的
                    ans.push_back(1.0);
                }else{
                    // 该数在equation中是不存在的,在图中也不存在
                    ans.push_back(-1.0);
                }
            }else{
                // 两数不相等
                unordered_set<string> visited; // 记录访问过的节点
                visited.insert(x[0]);
                // dfs 有向图两点是否存在路径
                if(dfs(x[0], x[1], 1.0, visited)){
                    // 存在路径
                    continue;
                }else{
                    // 不存在路径
                    ans.push_back(-1.0);
                }
            }
        }
        return ans;
    }

    bool dfs(string start, string end, double curAns, unordered_set<string>& visited){
        if(start == end){
            // 有节点
            ans.push_back(curAns);
            return true;
        }
        // 还没找到end的时候
        visited.insert(start);
        for(auto x: m[start]){
            if(visited.find(x.first) != visited.end()){
                // 以及访问过了x节点
                continue;
            }else{
                if(dfs(x.first, end, curAns * x.second, visited)){
                    // 如果有路径
                    return true;
                }
            }
        }
        return false;
    }
};

BFS

class Solution {
public:
    // 邻接图
    unordered_map<string, vector<pair<string, double>>> m; 
    // 答案
    vector<double> ans;

    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {

        // 初始化邻接图
        for(int i = 0; i < equations.size(); i++){
            m[equations[i][0]].push_back(pair<string, double>(equations[i][1], values[i]));
            m[equations[i][1]].push_back(pair<string, double>(equations[i][0], 1/values[i]));
        }
        // 遍历
        for(auto x: queries){
            if(x[0] == x[1]){
                // 除数和被除数一样
                if(m.find(x[0]) != m.end()){
                    // 数是存在的
                    ans.push_back(1.0);
                }else{
                    // 该数在equation中是不存在的,在图中也不存在
                    ans.push_back(-1.0);
                }
            }else{
                // dfs 有向图两点是否存在路径
                if(bfs(x[0], x[1])){
                    // 存在路径
                    continue;
                }else{
                    // 不存在路径
                    ans.push_back(-1.0);
                }
            }
        }
        return ans;
    }

    bool bfs(string start, string end){
        // bfs
        unordered_set<string> visited;

        queue<pair<string, double>> q;
        q.push(pair<string, double>(start, 1.0));

        visited.insert(start);

        while(!q.empty()){
            auto temp = q.front();
            q.pop();

            if(temp.first == end){
                // 找到了一条路径
                ans.push_back(temp.second);
                return true;
            }

            for(auto x: m[temp.first]){
                if(visited.find(x.first) != visited.end()){
                    // 如果出现在visited中了,之前已经访问过了该节点,跳过
                    continue;
                }else{
                    // 之前没有出现
                    q.push(pair<string, double>(x.first, x.second * temp.second));
                    visited.insert(x.first);
                }
            }
        }
        return false;
    }
};

802. 找到最终的安全状态

拓扑排序

class Solution {
public:
    vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
        int n = graph.size();

        vector<int> outDegree(n, 0); // out degree
        vector<vector<int>> revGraph(n, vector<int>{}); // reverse graph
        vector<int> ans;

        // init outDegree and revGraph
        for(int i = 0; i < n; i++){
            outDegree[i] = graph[i].size();
            for(auto end: graph[i]){
                revGraph[end].push_back(i); // reverse graph
            }
        }

        // 将出度为0的点放入队列
        queue<int> q;
        for(int i = 0; i < n; i++){
            if(outDegree[i] == 0){
                q.push(i);
            }
        }

        // 
        while(!q.empty()){

            auto temp = q.front();
            q.pop();
            // 找到出度为0的顶点,这些点是安全的点
            ans.push_back(temp);
            
            // 逆向删除以出度为0的顶点为弧头的边,弧尾的出度减一
            for(auto start: revGraph[temp]){
                outDegree[start]--;
                if(outDegree[start] == 0){
                    q.push(start);
                }
            }
        }

        sort(ans.begin(), ans.end());
        return ans;
    }
};

1203. 项目管理

分层拓扑排序 小组间 小组内

class Solution {
public:
    vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
        // 构造小组的依赖关系和组内项目的依赖关系。
        // 判断小组间是否有冲突,没冲突计算出小组的拓扑排序。
        // 判断每个小组内项目是否有冲突,没冲突计算出小组内项目的拓扑排序。
        // n个项目,m个小组
        // 拓扑排序
        int maxGroup = m;
        for(int i = 0; i < group.size(); i++){
            if(group[i] == -1){
                // 这个项目目前无人接手
                group[i]= maxGroup++;
            }
        }
        vector<set<int>> groupItem(maxGroup); // 小组内包含的项目
        vector<int> groupIndegree(maxGroup, 0); // 小组入度
        vector<set<int>> groupGraph(maxGroup); // 小组-图
        
        vector<int> itemIndegree(n, 0); // 每个小组内的项目入度
        vector<set<int>> itemGraph(n); // 每个小组内的项目图
        // 初始化groupItem,每个小组内包含了哪些任务
        for(int i = 0; i < group.size(); i++){
            groupItem[group[i]].insert(i);
        }
        // 初始化 小组入度
        for(int i = 0; i < beforeItems.size(); i++){
            for(auto bi: beforeItems[i]){
                if(group[i] == group[bi]){
                    // 属于同一个小组的时候
                    itemIndegree[i]++; 
                    itemGraph[bi].insert(i); // bi->i
                }else{
                    // 不属于同一个小组的时候 同样的两组之间不重复添加边
                    if(groupGraph[group[bi]].count(group[i]) == 0){
                        // bi->i bi所在的组
                        groupIndegree[group[i]]++; // i所在的组入度+1
                        groupGraph[group[bi]].insert(group[i]); // 构造图
                    }
                }
            }
        }
        // 小组 拓扑排序
        vector<int> ans;
        queue<int> q;
        // 入度为0 放入队列
        for(int i = 0; i < maxGroup; i++){
            if(groupIndegree[i] == 0){
                q.push(i);
            }
        }
        while(!q.empty()){
            auto temp = q.front();
            q.pop();
            ans.push_back(temp);
            for(auto& i: groupGraph[temp]){
                groupIndegree[i]--;
                if(groupIndegree[i] == 0){
                    q.push(i);
                }
            }
        }

        if(ans.size() != maxGroup){
            return vector<int>();
        }

        // 小组内排序
        vector<int> res;
        for(int i = 0; i < ans.size(); i++){
            for(auto& gi: groupItem[ans[i]]){
                if(itemIndegree[gi] == 0){
                    q.push(gi);
                }
            }
            int count = 0;
            while(!q.empty()){
                auto temp = q.front();
                q.pop();
                count++;
                res.push_back(temp);
                for(auto& ig: itemGraph[temp]){
                    itemIndegree[ig]--;
                    if(itemIndegree[ig] == 0){
                        q.push(ig);
                    }
                }
            }

            if(count != groupItem[ans[i]].size()){
                return vector<int>();
            }
        }
        return res;
    }
};

684. 冗余连接

并查集

class Solution {
public:
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        vector<int> rp(1001);
        int size = edges.size();

        // 初始化
        for(int i = 0; i < size; i++){
            rp[i] = i;
        }

        for(int i = 0; i < size; i++){
            int set1 = find(edges[i][0], rp);
            int set2 = find(edges[i][1], rp);

            if(set1 == set2){
                // 两个代表节点相同 出现了环,返回答案
                return edges[i];
            }else{
                // 两个集合独立,合并合集
                rp[set1] = set2;
            }
        }
        return {0, 0};
    }
    // 查找路径并返回代表节点,实际上就是给定当前节点,返回该节点所在集合的代表节点
    int find(int n, vector<int>& rp){
        int temp = n;
        while(rp[temp] != temp){
            temp = rp[temp];
        }
        return temp;
    }
};

你可能感兴趣的:(刷题,C++)