目录
LeetCode题解
chap-17:图论
1、岛屿数量
// 并查集+坐标变换
class UnionFind{
public:
vector<int> parent;
UnionFind(int n){
for(int i=0;i<n;i++)
parent.push_back(i);
}
int Find(int id){
if(parent[id] == id) return id;
parent[id] = Find(parent[id]);
return parent[id];
}
void Union(int a,int b){
int pa=Find(a);
int pb=Find(b);
parent[pb] = pa;
}
};
class Solution {
public:
int encode(int i,int j, int m){
return i*m+j;
}
int numIslands(vector<vector<char>>& grid) {
int dx[4]={-1,0,1,0}, dy[4]={0,1,0,-1};
int n=grid.size(), m=grid[0].size();
UnionFind UF(n*m);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(grid[i][j] == '1'){
for(int d = 0; d < 4; d++){
int di = dx[d], dj = dy[d];
if(i+di >=0 && i+di < n && j+dj >=0 &&
j+dj < m && grid[i+di][j+dj]=='1'){
UF.Union(encode(i, j, m), encode(i+di, j+dj, m));
}
}
}
}
}
int ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(grid[i][j] == '1'){
int id=encode(i,j,m);
if(UF.Find(id) == id) ans++;
}
return ans;
}
};
// dfs
class Solution {
public:
int res = 0;
int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1};
int numIslands(vector<vector<char>>& grid) {
for(int i = 0;i<grid.size();i++){
for(int j = 0;j<grid[0].size();j++){
if(grid[i][j] == '1'){
res++;
dfs(grid,i,j);
}
}
}
return res;
}
void dfs(vector<vector<char>>& g,int x,int y){
g[x][y] = '*';
for(int i = 0;i<4;i++){
int x_ = dx[i] + x, y_ = dy[i] + y;
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < g.size() && b >= 0 && b < g[a].size() && g[a][b] == '1')
dfs(g,a, b);
}
}
};
2、课程表 拓扑排序
class Solution {
public:
bool canFinish(int n, vector<vector<int>>& p) {
vector<int> in(n,0);
vector<vector<int>> g(n);
for(auto&t:p){
g[t[1]].push_back(t[0]);
in[t[0]]++;
}
queue<int> q;
vector<bool> f(n,false);
for(int i=0;i<n;i++) if(in[i]==0) q.push(i);
while(q.size()){
auto t=q.front();
f[t]=true;
for(auto &c:g[t]) {
in[c]--;
if(in[c] == 0) q.push(c);
}
q.pop();
}
for(bool t:f) if(!t) return false;
return true;
}
};
3、课程表 II
class Solution {
public:
vector<int> findOrder(int n, vector<vector<int>>& pres) {
vector<int> indegree(n,0);
vector<vector<int>> g(n);
for(auto &t:pres){
g[t[1]].push_back(t[0]); indegree[t[0]]++;
}
queue<int> q;
for(int i=0;i<n;i++) if(indegree[i]==0) q.push(i);
vector<bool> vis(n,false);
vector<int> ans;
while(q.size()){
auto t=q.front();
vis[t]=true;
ans.push_back(t); q.pop();
for(auto &c:g[t]){
indegree[c]--;
if(indegree[c]==0) q.push(c);
}
}
for(auto c:vis) if(!c) return vector<int>({});
return ans;
}
};
4、最小高度树 树形DP
// 树形模板
class Solution {
public:
int n;
vector<vector<int>>g;
vector<int> d1,d2,p1,up;
void dfs1(int u,int father){ // 向下遍历
for(auto x:g[u]){
if(x==father) continue;
dfs1(x,u);
int d = d1[x]+1;
if(d>=d1[u]){
d2[u]=d1[u], d1[u]=d;
p1[u]=x;
}else if(d>d2[u]) d2[u]=d;
}
}
void dfs2(int u,int father){ // 向上遍历
for(auto x:g[u]){
if(x==father) continue;
if(p1[u]==x) up[x] = max(up[u], d2[u])+1;
else up[x] = max(d1[u], up[u])+1;
dfs2(x,u);
}
}
vector<int> findMinHeightTrees(int m, vector<vector<int>>& edges) {
n=m; d1.resize(n); d2.resize(n); p1.resize(n); up.resize(n);
g.resize(n);
for(auto &t:edges) {
g[t[0]].push_back(t[1]);
g[t[1]].push_back(t[0]);
}
dfs1(0,-1);
dfs2(0,-1);
int mind=n-1;
vector<int> ans;
for(int i=0;i<n;i++){
auto t=max(d1[i],up[i]);
if(mind > t){
ans = vector<int>({});
ans.push_back(i);
mind = t;
}else if(mind == t) ans.push_back(i);
}
return ans;
}
};
// BFS
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if(n==1) return {0};
vector<int> degree(n); //节点对应的出度
vector<vector<int>> m(n); //邻接表
vector<int> res; //结果
for(auto &t:edges){
degree[t[0]]++; degree[t[1]]++;
m[t[0]].push_back(t[1]);
m[t[1]].push_back(t[0]);
}
queue<int> q;
//最外层叶子节点入栈
for(int i=0;i<n;i++) if(degree[i]==1) q.push(i);
//从外向内一层一层剥,每次加入的都是一层的
while(!q.empty()){
res.clear();
int sz=q.size();
for(int i=0;i<sz;i++){
int t=q.front(); q.pop();
res.push_back(t);
degree[t]--;
for(auto j:m[t]){
degree[j]--;
if(degree[j]==1) q.push(j);
}
}
}
return res;
}
};
5、重新安排行程 欧拉回路
class Solution {
public:
vector<string> ans;
unordered_map<string,multiset<string>> hash;
vector<string> findItinerary(vector<vector<string>>& tickets) {
for(auto &t:tickets){
hash[t[0]].insert(t[1]);
}
dfs("JFK");
return vector<string>(ans.rbegin(),ans.rend());
}
void dfs(string s){
while(hash[s].size()){
auto t=*hash[s].begin();
hash[s].erase(hash[s].begin());
dfs(t);
}
ans.push_back(s);
}
};
6、除法求值
class Solution {
public:
vector<double> calcEquation(vector<vector<string>>& es, vector<double>& vs, vector<vector<string>>& qs) {
// floyed
unordered_set<string> hash;
unordered_map<string,unordered_map<string,double>> g;
for(int i=0;i<es.size();i++){
auto a = es[i][0], b = es[i][1];
g[a][b] = vs[i], g[b][a] = 1 / vs[i];
hash.insert(a), hash.insert(b);
}
for(auto &k:hash)
for(auto &i:hash)
for(auto &j:hash)
if(g[i][k] && g[k][j])
g[i][j] = g[i][k]*g[k][j];
vector<double> ans;
for(auto q: qs) {
auto a = q[0], b = q[1];
if (g[a][b]) ans.push_back(g[a][b]);
else ans.push_back(-1);
}
return ans;
}
};
7、省份数量 【朋友圈】
// 并查集+坐标变换
class UnionFind{
public:
vector<int> parent;
UnionFind(int n){
for(int i=0;i<n;i++)
parent.push_back(i);
}
int Find(int id){
if(parent[id] == id) return id;
parent[id] = Find(parent[id]);
return parent[id];
}
void Union(int a,int b){
int pa=Find(a);
int pb=Find(b);
parent[pb] = pa;
}
};
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int n=isConnected.size();
UnionFind Uf(n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(isConnected[i][j]==1){
Uf.Union(i, j);
}
}
int ans=0;
for(int i=0;i<n;i++)
if(Uf.Find(i) == i) ans++;
return ans;
}
};
8、冗余连接 【并查集】
class Solution {
public:
int find(vector<int>&father, int id){
if(father[id]==id) return id;
father[id]=find(father,father[id]);
return father[id];
}
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
int n=edges.size();
vector<int> father(n+1);
for(int i=0;i<=n;i++)father[i]=i;
vector<int> ans(2,0);
for(auto &edge:edges){
int fa=find(father,edge[0]), fb=find(father,edge[1]);
if(fa==fb) ans[0]=edge[0], ans[1]=edge[1];
father[fa]=fb;
}
return ans;
}
};
9、网络延迟时间
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int n, int c) {
int dp[n+1][n+1];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) dp[i][j]=0;
else dp[i][j]=0x3f3f3f;
for(auto &t:times) dp[t[0]][t[1]]=t[2];
// floyd
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k][j]);
int ans=0;
for(int i=1;i<=n;i++){
if(dp[c][i]==0x3f3f3f) return -1;
else ans=max(ans,dp[c][i]);
}
return ans;
}
};
// spfa算法
class Solution {
public:
static const int N=110, M=6010, INF=0x3f3f3f3f;
int h[N], e[M], w[M], ne[M];
int eidx,n;
int dist[N];
bool st[N];
void add(int a,int b,int c){
e[eidx]=b, w[eidx]=c, ne[eidx]=h[a], h[a]=eidx++;
}
void spfa(int start){
queue<int> q;
q.push(start);
dist[start]=0;
while(q.size()){
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]){
if (dist[e[i]] > dist[t] + w[i]){
dist[e[i]] = dist[t] + w[i];
if (!st[e[i]])
{
st[e[i]] = true;
q.push(e[i]);
}
}
}
}
}
int networkDelayTime(vector<vector<int>>& times, int n_, int k) {
memset(h,-1,sizeof h);
eidx=0; n=n_;
for(auto &t:times) add(t[0],t[1],t[2]);
memset(dist,0x3f,sizeof dist);
memset(st,0,sizeof st);
spfa(k);
int ans=0;
for(int i=1;i<=n;i++){
if(dist[i]==INF) return -1;
else ans = max(ans,dist[i]);
}
return ans;
}
};
10、判断二分图 【×】
class Solution {
public:
bool isBipartite(vector<vector<int>>& graph) {
int n=graph.size();
vector<int> st(n,-1);
for(int i=0;i<n;i++)
if(st[i]==-1)
if(!dfs(graph,st,i,0))
return false;
return true;
}
bool dfs(vector<vector<int>>& graph, vector<int>&st, int u,int c){
st[u]=c;
for(auto a:graph[u]){
if(st[a] != -1) {
if(st[a]==c) return false;
}
else if(!dfs(graph, st, a, 1-c)) return false;
}
return true;
}
};
// bfs
class Solution {
public:
bool bfs(int S, vector<int>& color, const vector<vector<int>>& graph) {
color[S] = 0;
queue<int> q; q.push(S);
while (!q.empty()) {
int u = q.front();
q.pop();
for (auto &v : graph[u]) {
if (color[v] == color[u])
return false;
if (color[v] == -1) {
color[v] = 1 - color[u];
q.push(v);
}
}
}
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) {
if (!bfs(i, color, graph))
return false;
}
return true;
}
};
11、所有可能的路径 dfs
class Solution {
public:
int n;
vector<bool> f;
vector<int> path;
vector<vector<int>> ans;
vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
n=graph.size();
f.resize(n);
dfs(graph,0);
return ans;
}
void dfs(vector<vector<int>>& graph, int u){
if(u == n-1 && !f[u]){
path.push_back(u);
ans.emplace_back(path);
path.pop_back();
}else if(!f[u]){
f[u]=true;
path.push_back(u);
for(auto t:graph[u]){
dfs(graph, t);
}
path.pop_back();
f[u]=false;
}
}
};
12、等式方程的可满足性
class Solution {
public:
int Find(vector<int>& father, int id){
if(father[id]==id) return id;
father[id]=Find(father, father[id]);
return father[id];
}
bool equationsPossible(vector<string>& equations) {
vector<int> father(26);
for(int i=0;i<26;i++) father[i]=i;
for(auto &eq:equations){
int a = eq[0]-'a', b = eq[3]-'a';
if(eq[1]=='='){
int fa=Find(father, a);
int fb=Find(father, b);
father[fa]=fb;
}
}
for(auto &eq:equations){
int a = eq[0]-'a', b = eq[3]-'a';
if(eq[1]=='!'){
int fa=Find(father, a);
int fb=Find(father, b);
if(fa==fb) return false;
}
}
return true;
}
};
13、连接所有点的最小费用 【最小生成树】
class Solution {
private:
int calc(vector<int> &x, vector<int> &y) {
return abs(x[0] - y[0]) + abs(x[1] - y[1]);
}
public:
int minCostConnectPoints(vector<vector<int>>& points) {
// prim算法
const int n = points.size();
vector<bool> vis(n, false);
vector<int> dis(n, INT_MAX);
int ans = 0;
dis[0] = 0;
for (int i = 0; i < n; i++) {
int mindis = INT_MAX;
int m = -1;
for (int j = 0; j < n; j++)
if (!vis[j] && mindis > dis[j]) {
mindis = dis[j];
m = j;
}
vis[m] = true;
ans += mindis;
for (int j = 0; j < n; j++)
dis[j] = min(dis[j], calc(points[m], points[j]));
}
return ans;
}
};
[Go Back~](# LeetCode题解)