数据结构-图
- 判断是否为二分图 785. Is Graph Bipartite?(Medium)
- 判断是否可能为二分图 886. Possible Bipartition(Medium)
- 拓扑排序:课程安排的合法性 207. Course Schedule(Medium)
- 课程安排的顺序 210. Course Schedule II(Medium)
- 冗余连接,并查集 684. Redundant Connection(Medium)
- 联通分量的个数 547. Number of Provinces(Medium)
- 找安全节点 802. Find Eventual Safe States(Medium)
- 相似字符串组 839. Similar String Groups(Hard)
简答总结:
- 二分图判定:可转化为染色问题,DFS可解
- 拓扑排序:从入度为0的节点开始BFS,遍历过程中更新入度将入度为0的push到队列中
- 联通分量个数:并查集
- 图中找环:DFS
- 并查集
判断是否为二分图
class Solution {
public:
bool dfs(vector<vector<int>>& graph, vector<int>& color, int node, int c){
color[node] = c;
int result = true;
for(int i = 0;i < graph[node].size(); i++){
if(color[graph[node][i]] == -1 && !dfs(graph, color, graph[node][i], 1-c))
return false;
else if(color[graph[node][i]] != 1-c){
return false;
}
}
return true;
}
bool isBipartite(vector<vector<int>>& graph) {
int n = graph.size();
vector<int> color(n, -1);
for(int i = 0;i < n; i++){
if(color[i] == -1 && !dfs(graph, color, i, 0))
return false;
}
return true;
}
};
判断是否可能为二分图
class Solution {
public:
bool dfs(vector<vector<int>>& graph, vector<int>& color, int index, int c){
if(color[index] != -1)
return color[index] == c;
color[index] = c;
for(int u: graph[index]){
if(color[u] != -1 && color[u] != 1-c)
return false;
if(color[u] == -1 && !dfs(graph, color, u, 1-c))
return false;
}
return true;
}
bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
// 用0,1进行染色,-1表示未染色
vector<vector<int>> graph(n+1);
vector<int> color(n+1, -1);
for(vector<int>& v: dislikes){
graph[v[0]].push_back(v[1]);
graph[v[1]].push_back(v[0]);
}
for(int i = 0;i < n; i++){
if(color[i] == -1 && !dfs(graph, color, i, 0))
return false;
}
return true;
}
};
拓扑排序:课程安排的合法性
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& pre) {
/*
思路:BFS,队列中保存入度为0的节点,然后不断删除入度为0的节点,删除后把该节点连上的节点入度-1
时间复杂度:O(n^2)
空间复杂度:O(n^2) 可能是全连接图
*/
vector<int> indegree(numCourses, 0);
vector<vector<int> > graph(numCourses);
for(int i = 0;i < pre.size(); i++){
graph[pre[i][1]].push_back(pre[i][0]);
indegree[pre[i][0]] += 1;
}
int done = 0;
queue<int> q;
for(int i = 0;i < numCourses; i++){
if(indegree[i] == 0){
q.push(i);
done += 1;
}
}
while(!q.empty()){
int node = q.front();
q.pop();
for(int i = 0;i < graph[node].size(); i++){
indegree[graph[node][i]] -= 1;
if(indegree[graph[node][i]] == 0){
q.push(graph[node][i]);
done += 1;
}
}
}
return done == numCourses;
}
};
课程安排的顺序
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& pre) {
vector<int> indegree(numCourses, 0);
vector<vector<int> > graph(numCourses);
for(int i = 0;i < pre.size(); i++){
graph[pre[i][1]].push_back(pre[i][0]);
indegree[pre[i][0]] += 1;
}
vector<int> order;
queue<int> q;
for(int i = 0;i < numCourses; i++){
if(indegree[i] == 0){
q.push(i);
order.push_back(i);
}
}
while(!q.empty()){
int node = q.front();
q.pop();
for(int i = 0;i < graph[node].size(); i++){
indegree[graph[node][i]] -= 1;
if(indegree[graph[node][i]] == 0){
q.push(graph[node][i]);
order.push_back(graph[node][i]);
}
}
}
vector<int> empty;
return order.size() == numCourses ? order : empty;
}
};
冗余连接,并查集
class Solution {
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
int parent[1005];
for(int i = 0;i < 1005; i++)
parent[i] = i;
int ans_index = 0;
for(int i = 0;i < edges.size(); i++){
int u = edges[i][0], v = edges[i][1];
if(find(parent, u) == find(parent, v)){
ans_index = i;
}
else
union_node(parent, u, v);
}
return edges[ans_index];
}
int find(int* parent, int node){
if(parent[node] == node)
return node;
return parent[node] = find(parent, parent[node]);
}
void union_node(int* parent, int u, int v){
int up = find(parent, u);
int vp = find(parent, v);
if(up == vp)
return ;
else
parent[up] = vp;
}
};
联通分量的个数
两种方法:DFS和并查集
class Solution {
public:
void dfs(vector<vector<int>>& isConnected, vector<int>& visited, int index){
visited[index] = 1;
int n = isConnected.size();
for(int i = 0;i < n; i++){
if(isConnected[index][i] == 1 && visited[i] == 0)
dfs(isConnected, visited, i);
}
}
int findCircleNum_dfs(vector<vector<int>>& isConnected) {
// DFS
int n = isConnected.size(), cnt = 0;
vector<int> visited(n, 0);
for(int i = 0;i < n; i++){
if(visited[i] == 0){
dfs(isConnected, visited, i);
cnt += 1;
}
}
return cnt;
}
int findCircleNum(vector<vector<int>>& isConnected) {
// 并查集
int n = isConnected.size(), cnt = 0;
vector<int> parent(n, 0);
for(int i = 0;i < n; i++)
parent[i] = i;
for(int i = 0;i < n; i++){
for(int j = i+1;j < n; j++)
if(isConnected[i][j] == 1 && find(parent, i) != find(parent, j))
union_node(parent, i, j);
}
for(int i = 0;i < n; i++){
if(parent[i] == i)
cnt += 1;
}
return cnt;
}
int find(vector<int>& parent, int i){
if(parent[i] == i)
return i;
return parent[i] = find(parent, parent[i]);
}
void union_node(vector<int>& parent, int i, int j){
int ip = parent[i];
int jp = parent[j];
if(ip != jp)
parent[ip] = jp;
}
};
找安全节点
class Solution {
public:
enum State {VISITING, SAFE, UNSAFE, UNK};
State dfs(vector<vector<int> >& graph, vector<State>& states, int node){
if(states[node] == VISITING)
return states[node] = UNSAFE;
if(states[node] == UNSAFE || states[node] == SAFE) // node只要不是unk则说明在此之前已经经过了检查,则无论safe还是unsafe都可直接返回
return states[node];
states[node] = VISITING;
for(int next: graph[node]){
if(dfs(graph, states, next) == UNSAFE)
return states[node] = UNSAFE;
}
return states[node] = SAFE;
}
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
int n = graph.size();
vector<State> states(n, UNK);
vector<int> ans;
for(int i = 0;i < n; i++){
if(dfs(graph, states, i) == SAFE)
ans.push_back(i);
}
return ans;
}
};
相似字符串组
class Solution {
public:
bool equal(string& s1, string& s2){
if(s1.size() != s2.size())
return false;
int i = -1, j = -1;
for(int k = 0;k < s1.size(); k++){
if(s1[k] != s2[k]){
if(i != -1 && j != -1)
return false;
else if(i == -1)
i = k;
else if(j == -1)
j = k;
}
}
if(i == -1 && j == -1)
return true;
return s1[i] == s2[j] && s1[j] == s2[i];
}
int numSimilarGroups(vector<string>& strs) {
int n = strs.size();
vector<int> parent(n);
for(int i = 0;i < n; i++)
parent[i] = i;
for(int i = 1;i < n; i++){
for(int j = 0;j < i; j++){
if(equal(strs[i], strs[j]))
union_node(parent, i, j);
}
}
int ans = 0;
for(int i = 0;i < n; i++){
if(parent[i] == i)
ans += 1;
}
return ans;
}
int find(vector<int>& parent, int u){
if(parent[u] == u)
return u;
return parent[u] = find(parent, parent[u]);
}
void union_node(vector<int>& parent, int u, int v){
int up = find(parent, u);
int vp = find(parent, v);
if(up != vp)
parent[vp] = up;
}
};