LeetCode 图

207. 课程表

超时解法:

class Solution {

    bool dfs(vector<vector<int>>& graph, int i, vector<int> courses){
        for(int j = 0; j < courses.size(); j++){
            if(courses[j] == i)return false;
        }
        courses.emplace_back(i);
        for(int j = 0; j < graph.size(); j++){
            if(graph[i][j]){
                if(!dfs(graph, j, courses))return false;
            }
        }
        return true;
    }

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        if(prerequisites.size() == 0)return true;
        vector<vector<int>> graph(numCourses, vector<int>(numCourses));
        for(int i = 0; i < prerequisites.size(); i++){
            int a = prerequisites[i][0], b = prerequisites[i][1];
            graph[a][b] = 1;
        }
        
        vector<int> courses;
        for(int i = 0; i < numCourses; i++){
            if(!dfs(graph, i, courses))return false;
        }
        return true;
    }
};

优化了一下,使用 n u m C o u r c e s numCources numCources维的cources来标记当前是否遍历到,使用tranverse标记历史是否遍历到这门课,若遍历到下一次不需要再遍历。过了上次的超时用例,但是又来了新的超时用例。

class Solution {
    bool dfs(vector<vector<int>>& graph, int i, vector<int>& courses, vector<int>& traverse){
        if(courses[i] == 1)return false;
        traverse[i] = 1;
        for(int j = 0; j < graph.size(); j++){
            if(graph[i][j]){
                courses[i] = 1;
                if(traverse[i] == 1 && courses[i] == 0)continue;
                if(!dfs(graph, j, courses, traverse))return false;
                courses[i] = 0;
            }
        }
        return true;
    }

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        if(prerequisites.size() == 0)return true;
        vector<vector<int>> graph(numCourses, vector<int>(numCourses));
        for(int i = 0; i < prerequisites.size(); i++){
            int a = prerequisites[i][0], b = prerequisites[i][1];
            graph[a][b] = 1;
        }

        vector<int> traverse(numCourses);
        for(int i = 0; i < numCourses; i++){
            if(traverse[i] == 0){
                vector<int> courses(numCourses);
                if(!dfs(graph, i, courses, traverse))return false;
            }
        }
        return true;
    }
};
/*
5
[[0,2],[2,1],[3,1],[1,4],[4,1]]
*/

参考题解,只是用一个数组来标记不同状态,只需要将其置为不同的值即可,比如用1表示当前遍历过的,用2表示已经遍历成功的课。

正确解法:

class Solution {

    bool dfs(vector<vector<int>>& graph, int i, vector<int>& traverse){
        traverse[i] = 1;
        for(int j = 0; j < graph.size(); j++){
            if(graph[i][j]){
                if(traverse[j] == 1){
                    return false;
                }
                if(traverse[j] == 0){
                    if(!dfs(graph, j, traverse))return false;
                }
            }
        }
        traverse[i] = 2;
        return true;
    }

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        if(prerequisites.size() == 0)return true;
        vector<vector<int>> graph(numCourses, vector<int>(numCourses));
        for(int i = 0; i < prerequisites.size(); i++){
            int a = prerequisites[i][0], b = prerequisites[i][1];
            graph[a][b] = 1;
        }

        vector<int> traverse(numCourses);
        for(int i = 0; i < numCourses; i++){
            if(traverse[i] == 0){
                if(!dfs(graph, i, traverse))return false;
            }
        }
        return true;
    }
};

结果:
在这里插入图片描述
还是很慢,可以不使用邻接矩阵,将graph[i]向量存储课程i的先修课程序列。

310. 最小高度树

注意,树的高度是所有子树高度的最大值+1.

又是超时!
超时代码:

class Solution {
    vector<vector<int>> graph;
    int min_len = 999999;

    int getLevel(int node, int parent, int len){
        if(len > min_len)return len;
        if(graph[node].size() == 1 && graph[node][0] == parent){
            return len;
        }
        int now_len = 0;
        for(int i = 0; i < graph[node].size(); i++){
            if(graph[node][i] != parent){
                now_len = max(now_len, getLevel(graph[node][i], node, len + 1));
            }
        }
        return now_len;
    }

public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
        vector<int> res;
        if(n == 1){
            res.push_back(0);
            return res;
        }

        graph.resize(n);
        for(int i = 0; i < edges.size(); i++){
            graph[edges[i][0]].push_back(edges[i][1]);
            graph[edges[i][1]].push_back(edges[i][0]);
        }
        
        for(int i = 0; i < n; i++){
            int len = getLevel(i, -1, 1);
            if(len < min_len){
                min_len = len;
                res.clear();
                res.push_back(i);
            }
            else if(len == min_len)res.push_back(i);
        }
        return res;
    }
};

看了下题解,果然最优思路不是暴力来做的,再优化还是很慢。
从图的边缘开始缩小图,每次将度为1的节点删除。使用队列来做,最后的队列就是答案。

正确解法:

class Solution {

public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
        vector<int> res;
        if(n == 1){
            res.push_back(0);
            return res;
        }

        vector<vector<int>> graph(n);
        vector<int> du(n);
        for(int i = 0; i < edges.size(); i++){
            graph[edges[i][0]].push_back(edges[i][1]);
            graph[edges[i][1]].push_back(edges[i][0]);
            du[edges[i][0]]++;
            du[edges[i][1]]++;
        }

        queue<int> que;
        for(int i = 0; i < n; i++){
            if(du[i] <= 1)que.push(i);
        }

        while(que.size() != n){
            int size = que.size();
            n -= size;
            while(size--){
                int q = que.front();
                que.pop();

                for(int i = 0; i < graph[q].size(); i++){
                    int j = graph[q][i];
                    du[j]--;
                    if(du[j] == 1){
                        que.push(j);
                    }
                }
            }
        }

        for(int i = 0; i < n; i++){
            res.push_back(que.front());
            que.pop();
        }
        return res;
    }
};

结果:
在这里插入图片描述

399. 除法求值

使用unordered_map来完成字符串到索引的映射,注意要使用 t r a n v e r s e tranverse tranverse来标记某节点是否被遍历过,或遍历过则说明程序跳进了循环,直接返回false。

递归解法:

class Solution {

    bool dfs(vector<vector<pair<int, double>>>& graph, int x, int goal, int parent, double& res, vector<int>& tranverse){
        if(tranverse[x] == 1)return false;
        if(x == goal){
            return true;
        }
        tranverse[x] = 1;
        for(int i = 0; i < graph[x].size(); i++){
            int nxt = graph[x][i].first;
            if(nxt == parent)continue;
            res *= graph[x][i].second;
            if(dfs(graph, nxt, goal, x, res, tranverse))return true;
            res /= graph[x][i].second;
        }
        return false;
    }
    

public:
    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
        unordered_map<string, int> m;
        vector<double> result;

        int num = 0;
        for(int i = 0; i < equations.size(); i++){
            if(m.find(equations[i][0]) == m.end()){
                m[equations[i][0]] = num++;
            }
            if(m.find(equations[i][1]) == m.end()){
                m[equations[i][1]] = num++;
            }
        }

        vector<vector<pair<int, double>>> graph(num);
        for(int i = 0; i < equations.size(); i++){
            int a = m[equations[i][0]], b = m[equations[i][1]];
            if(a == b)continue;
            graph[a].push_back(make_pair(b, values[i]));
            graph[b].push_back(make_pair(a, 1 / values[i]));
        }
        
        /*for(auto it = m.begin(); it != m.end(); it++){
            cout << it->first << " " << it->second << endl;
        }

        for(int i = 0; i < graph.size(); i++){
            cout << "----------" << i << endl;
            for(int j = 0; j < graph[i].size(); j++){
                cout << graph[i][j].first << " " << graph[i][j].second << endl;
            }
        }*/
        
        for(int i = 0; i < queries.size(); i++){
            if(m.find(queries[i][0]) == m.end() || m.find(queries[i][1]) == m.end()){
                result.push_back(-1.0);
                continue;
            }
            int a = m[queries[i][0]], b = m[queries[i][1]];
            double res = 1.0;
            // cout << "cal " << a << " " << b << endl;
            vector<int> tranverse(num);
            if(dfs(graph, a, b, -1, res, tranverse)){
                result.push_back(res);
            }
            else{
                result.push_back(-1.0);
            }
            // cout << "res " << res << endl;
        }
        return result;
    }
}; 

结果:
在这里插入图片描述

使用队列来完成非递归算法,其中使用数组 t e m p temp temp来存储中间值,初始化为-1.0。当遍历到节点i时,若 t e m p [ i ] ! = − 1.0 temp[i]!=-1.0 temp[i]!=1.0时,则说明该节点被遍历过,因此直接跳过。

非递归解法:

class Solution {
public:
    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
        unordered_map<string, int> m;
        vector<double> result;

        int num = 0;
        for(int i = 0; i < equations.size(); i++){
            if(m.find(equations[i][0]) == m.end()){
                m[equations[i][0]] = num++;
            }
            if(m.find(equations[i][1]) == m.end()){
                m[equations[i][1]] = num++;
            }
        }

        vector<vector<pair<int, double>>> graph(num);
        for(int i = 0; i < equations.size(); i++){
            int a = m[equations[i][0]], b = m[equations[i][1]];
            if(a == b)continue;
            graph[a].push_back(make_pair(b, values[i]));
            graph[b].push_back(make_pair(a, 1 / values[i]));
        }
        
        /*for(auto it = m.begin(); it != m.end(); it++){
            cout << it->first << " " << it->second << endl;
        }

        for(int i = 0; i < graph.size(); i++){
            cout << "----------" << i << endl;
            for(int j = 0; j < graph[i].size(); j++){
                cout << graph[i][j].first << " " << graph[i][j].second << endl;
            }
        }*/
        
        for(int i = 0; i < queries.size(); i++){
            if(m.find(queries[i][0]) == m.end() || m.find(queries[i][1]) == m.end()){
                result.push_back(-1.0);
                continue;
            }
            int a = m[queries[i][0]], b = m[queries[i][1]];
            double res = 1.0;
            queue<int> que;
            que.push(a);
            vector<double> temp(num, -1.0);
            temp[a] = 1.0;  
            while(temp[b] == -1.0 && !que.empty()){
                int x = que.front();
                que.pop();
                for(int j = 0; j < graph[x].size(); j++){
                    int k = graph[x][j].first;
                    if(temp[k] == -1.0){
                        que.push(k);
                        temp[k] = temp[x] * graph[x][j].second;
                    }
                }
            }
            result.push_back(temp[b]);
        }
        return result;
    }
}; 

结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值