• 785. 判断二分图-7月16日


    题目

    785. 判断二分图

    我的思路

    我自己做的方法对于简单测试用例可行,但提交后遇到大的测试用例因为复杂度过高无法运行。

    我的思路是这样:实质上就是找一种分类A和B:i属于A时,若j属于B,graph[i]中一定没有j;反之亦然

    整理一下思路:
    递归的出口条件:遍历完最后一个节点i=graph.length or 两个集合中存在重复元素
    check(int i,vector<vector<int>>& graph,vector<int> A,vector<int> B,int type)递归函数内部的执行过程:
    0.如果i等于graph.length,那么返回true
    1.把i加入A,把graph[i]中所有元素加入B
    2.判断A和B中是否有重复元素,若有返回false
    3.bool R1 = check(graph,A,B,0)
    4.bool R2 = check(graph,A,B,1)
    5.return R1 || R2
    时间复杂度:2^n,因为是递归且递归函数中有两个递归调用

    我的实现

    class Solution {
    public:
        bool isBipartite(vector<vector<int>>& graph) {
            set<int> A,B;
            return check(0,graph,A,B,0);
        }
        bool check(int i,vector<vector<int>>& graph,set<int> A,set<int> B,int type){
            if(i==graph.size()) return true;//0.如果i等于graph.length,那么返回true
            if(type == 0){//1.把i加入A,把graph[i]中所有元素加入B
                A.insert(i);
                for(auto iter : graph[i])   B.insert(iter);
            }else{
                B.insert(i);
                for(auto iter : graph[i])   A.insert(iter);
            }
            for(auto iter: A){//2.判断A和B中是否有重复元素,若有返回false
                if(B.count(iter)>0) return false;
            }
            bool R1 = check(i+1,graph,A,B,0);
            if(R1==true)return true;
            bool R2 = check(i+1,graph,A,B,1);
            return R1 || R2;
    
        }
    
    };
    /**
    重新整理一下思路:
    递归的出口条件:遍历完最后一个节点i=graph.length or 两个集合中存在重复元素
    check(int i,vector<vector<int>>& graph,vector<int> A,vector<int> B,int type)递归函数内部的执行过程:
    0.如果i等于graph.length,那么返回true
    1.把i加入A,把graph[i]中所有元素加入B
    2.判断A和B中是否有重复元素,若有返回false
    3.bool R1 = check(graph,A,B,0)
    4.bool R2 = check(graph,A,B,1)
    5.return R1 || R2
    */
    
    /**
    实质上就是找一种分类A和B:
    i属于A时,若j属于B,graph[i]中一定没有j;反之亦然
    1.强行暴力枚举所有分类的话,时间复杂度会达到2^n以上
    2.遍历graph,对每个graph[i],可以产生两种结果: 
        graph[i]中的元素属于A,i属于B    or     graph[i]中的元素属于B,i属于A
        接着检查是否与现有集合有冲突,若没有则继续,若有则返回
    */

    时间复杂度过大!换思路

    class Solution {
    public:
        bool isBipartite(vector<vector<int>>& graph) {
            int constexpr NOCOLOR=0;
            int constexpr RED=1;
            int constexpr GREEN=2;
            int numofNodes=graph.size();
            vector<int> nodestocheck;
            vector<int> colors(numofNodes,NOCOLOR);
            //colors[0]=RED;
            //nodestocheck.push_back(0);
            for(int i=0;i<numofNodes;i++){
                if(colors[i]!=NOCOLOR)continue;
                colors[i]=RED;
                printf("%din
    ",i);
                nodestocheck.push_back(i);
                while(!nodestocheck.empty()){
                    int presentNode = *nodestocheck.begin();
                    nodestocheck.erase(nodestocheck.begin());
                    printf("%dout
    ",presentNode);
                    for(auto iter:graph[presentNode]){
                        if(colors[iter]==colors[presentNode]){
                            //printf("%d:%d:%d",colors[iter],iter,presentNode);
                            return false;
                        }else
                        if(colors[iter]==NOCOLOR){
                            colors[iter]= colors[presentNode]==RED?GREEN:RED;
                            nodestocheck.push_back(iter);
                            printf("%din
    ",iter);
                        }
                    }
                }
            }
            return true;
        }
    
    };

    以上是我的广搜实现

    拓展学习

    constexpr

    https://blog.csdn.net/u011469662/article/details/96866034

    语义上:
    constexpr:告诉编译器我可以是编译期间可知的,尽情的优化我吧。
    const:告诉程序员没人动得了我,放心的把我传出去;或者放心的把变量交给我,我啥也不动就瞅瞅。

    语法上:
    constexpr是一种比const 更严格的束缚, 它修饰的表达式本身在编译期间可知, 并且编译器会尽可能的 evaluate at compile time. 在constexpr 出现之前, 可以在编译期初始化的const都是implicit constexpr. 直到c++ 11, constexpr才从const中细分出来成为一个关键字, 而 const从1983年 c++ 刚改名的时候就存在了… 如果你初学c++, 应当尽可能的, 合理的使用constexpr来帮助编译器优化代码.

    深度优先搜索

    class Solution {
    private:
        static constexpr int UNCOLORED = 0;
        static constexpr int RED = 1;
        static constexpr int GREEN = 2;
        vector<int> color;
        bool valid;
    
    public:
        void dfs(int node, int c, const vector<vector<int>>& graph) {
            color[node] = c;
            int cNei = (c == RED ? GREEN : RED);
            for (int neighbor: graph[node]) {
                if (color[neighbor] == UNCOLORED) {
                    dfs(neighbor, cNei, graph);
                    if (!valid) {
                        return;
                    }
                }
                else if (color[neighbor] != cNei) {
                    valid = false;
                    return;
                }
            }
        }
    
        bool isBipartite(vector<vector<int>>& graph) {
            int n = graph.size();
            valid = true;
            color.assign(n, UNCOLORED);
            for (int i = 0; i < n && valid; ++i) {
                if (color[i] == UNCOLORED) {
                    dfs(i, RED, graph);
                }
            }
            return valid;
        }
    };

    时间复杂度:O(N+M)O(N+M),其中 NN 和 MM 分别是无向图中的点数和边数。

    空间复杂度:O(N)O(N),存储节点颜色的数组需要 O(N)O(N) 的空间,并且在深度优先搜索的过程中,栈的深度最大为 NN,需要 O(N)O(N) 的空间。

    转自leetcode官方题解

    广度优先搜索

    class Solution {
    private:
        static constexpr int UNCOLORED = 0;
        static constexpr int RED = 1;
        static constexpr int GREEN = 2;
        vector<int> color;
    
    public:
        bool isBipartite(vector<vector<int>>& graph) {
            int n = graph.size();
            vector<int> color(n, UNCOLORED);
            for (int i = 0; i < n; ++i) {
                if (color[i] == UNCOLORED) {
                    queue<int> q;
                    q.push(i);
                    color[i] = RED;
                    while (!q.empty()) {
                        int node = q.front();
                        int cNei = (color[node] == RED ? GREEN : RED);
                        q.pop();
                        for (int neighbor: graph[node]) {
                            if (color[neighbor] == UNCOLORED) {
                                q.push(neighbor);
                                color[neighbor] = cNei;
                            }
                            else if (color[neighbor] != cNei) {
                                return false;
                            }
                        }
                    }
                }
            }
            return true;
        }
    };

    时间复杂度:O(N+M)O(N+M),其中 NN 和 MM 分别是无向图中的点数和边数。

    空间复杂度:O(N)O(N),存储节点颜色的数组需要 O(N)O(N) 的空间,并且在广度优先搜索的过程中,队列中最多有 N-1N−1 个节点,需要 O(N)O(N) 的空间。

    转自leetcode官方题解

  • 相关阅读:
    C++教程_w3cschool
    C++教程|菜鸟教程
    C++编程兵书
    学习C++从入门到精通的的十本最经典书籍
    从大公司到创业公司,技术人转型怎样转变思路与处事之道?
    c# 与 c++ 交互
    c++ 使用vs2010调用 win32api
    Excel学习笔记
    Windows环境变量设置无效解决办法——DOS窗口设置环境变量
    MAVEN ERROR: unable to find valid certification path to requested target 解决办法
  • 原文地址:https://www.cnblogs.com/BoysCryToo/p/13321832.html
Copyright © 2020-2023  润新知