题目
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,那么返回true1.把i加入A,把graph[i]中所有元素加入B2.判断A和B中是否有重复元素,若有返回false3.bool R1 = check(graph,A,B,0)4.bool R2 = check(graph,A,B,1)5.return R1 || R2
我的实现
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官方题解