Given an undirected graph consisting of V vertices and E edges. The graph is represented as a 2D array edges[][], where each element edges[i] = [u, v] denotes an undirected edge between vertices u and v. Find all the articulation points in the graph. If no such points exist, return {-1}.
An articulation point is a vertex whose removal, along with all its connected edges, increases the number of connected components in the graph.
Note: The graph may be disconnected, meaning it can consist of multiple connected components.
[Naive Approach] - DFS - O(V Ă— (V + E)) Time and O(V) Space
The idea is to traverse all the vertices and do the following to check if it is an articulation point or not.
Remove the chosen vertex and call DFS (Depth First Search) on its neighbors.
If DFS needs to be called more than once (i.e., multiple disconnected components are formed), then removing that vertex increases the number of components, so it is an articulation point.
C++
#include<bits/stdc++.h>usingnamespacestd;voiddfs(intnode,vector<vector<int>>&adj,vector<bool>&visited){visited[node]=true;for(intneighbor:adj[node]){if(!visited[neighbor])dfs(neighbor,adj,visited);}}vector<int>articulationPoints(intV,vector<vector<int>>&edges){vector<vector<int>>adj(V);// Build adjacency listfor(autoedge:edges){intu=edge[0];intv=edge[1];adj[u].push_back(v);adj[v].push_back(u);}vector<int>ans;// Try removing every vertexfor(inti=0;i<V;i++){vector<bool>visited(V,false);visited[i]=true;intcomponents=0;// Run DFS from each unvisited neighborfor(intneighbor:adj[i]){if(!visited[neighbor]){dfs(neighbor,adj,visited);components++;}}// More than one component means articulation pointif(components>1)ans.push_back(i);}if(ans.empty())ans.push_back(-1);returnans;}intmain(){intV=5;vector<vector<int>>edges={{0,1},{1,4},{4,3},{4,2},{2,3}};vector<int>ans=articulationPoints(V,edges);for(intx:ans)cout<<x<<" ";return0;}
Java
importjava.util.ArrayList;classGFG{staticvoiddfs(intnode,ArrayList<ArrayList<Integer>>adj,boolean[]visited){visited[node]=true;for(intneighbor:adj.get(node)){if(!visited[neighbor])dfs(neighbor,adj,visited);}}staticArrayList<Integer>articulationPoints(intV,int[][]edges){ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<V;i++)adj.add(newArrayList<>());// Build adjacency listfor(int[]edge:edges){intu=edge[0];intv=edge[1];adj.get(u).add(v);adj.get(v).add(u);}ArrayList<Integer>ans=newArrayList<>();// Try removing every vertexfor(inti=0;i<V;i++){boolean[]visited=newboolean[V];visited[i]=true;intcomponents=0;// Run DFS from each unvisited neighborfor(intneighbor:adj.get(i)){if(!visited[neighbor]){dfs(neighbor,adj,visited);components++;}}// More than one component means articulation pointif(components>1)ans.add(i);}if(ans.isEmpty())ans.add(-1);returnans;}publicstaticvoidmain(String[]args){intV=5;int[][]edges={{0,1},{1,4},{4,3},{4,2},{2,3}};ArrayList<Integer>ans=articulationPoints(V,edges);for(intx:ans)System.out.print(x+" ");}}
Python
defdfs(node,adj,visited):visited[node]=Trueforneighborinadj[node]:ifnotvisited[neighbor]:dfs(neighbor,adj,visited)defarticulationPoints(V,edges):adj=[[]for_inrange(V)]# Build adjacency listforu,vinedges:adj[u].append(v)adj[v].append(u)ans=[]# Try removing every vertexforiinrange(V):visited=[False]*Vvisited[i]=Truecomponents=0# Run DFS from each unvisited neighborforneighborinadj[i]:ifnotvisited[neighbor]:dfs(neighbor,adj,visited)components+=1# More than one component means articulation pointifcomponents>1:ans.append(i)ifnotans:ans.append(-1)returnansif__name__=="__main__":V=5edges=[[0,1],[1,4],[4,3],[4,2],[2,3]]ans=articulationPoints(V,edges)print(*ans)
C#
usingSystem;usingSystem.Collections.Generic;classGFG{staticvoiddfs(intnode,List<List<int>>adj,bool[]visited){visited[node]=true;foreach(intneighborinadj[node]){if(!visited[neighbor])dfs(neighbor,adj,visited);}}staticList<int>articulationPoints(intV,List<List<int>>edges){List<List<int>>adj=newList<List<int>>();for(inti=0;i<V;i++)adj.Add(newList<int>());// Build adjacency listforeach(List<int>edgeinedges){intu=edge[0];intv=edge[1];adj[u].Add(v);adj[v].Add(u);}List<int>ans=newList<int>();// Try removing every vertexfor(inti=0;i<V;i++){bool[]visited=newbool[V];visited[i]=true;intcomponents=0;// Run DFS from each unvisited neighborforeach(intneighborinadj[i]){if(!visited[neighbor]){dfs(neighbor,adj,visited);components++;}}// More than one component means articulation pointif(components>1)ans.Add(i);}if(ans.Count==0)ans.Add(-1);returnans;}staticvoidMain(){intV=5;List<List<int>>edges=newList<List<int>>{newList<int>{0,1},newList<int>{1,4},newList<int>{4,3},newList<int>{4,2},newList<int>{2,3}};List<int>ans=articulationPoints(V,edges);foreach(intxinans)Console.Write(x+" ");}}
JavaScript
functiondfs(node,adj,visited){visited[node]=true;for(letneighborofadj[node]){if(!visited[neighbor]){dfs(neighbor,adj,visited);}}}functionarticulationPoints(V,edges){letadj=Array.from({length:V},()=>[]);// Build adjacency listfor(let[u,v]ofedges){adj[u].push(v);adj[v].push(u);}letans=[];// Try removing every vertexfor(leti=0;i<V;i++){letvisited=newArray(V).fill(false);visited[i]=true;letcomponents=0;// Run DFS from each unvisited neighborfor(letneighborofadj[i]){if(!visited[neighbor]){dfs(neighbor,adj,visited);components++;}}// More than one component means articulation pointif(components>1){ans.push(i);}}if(ans.length===0){ans.push(-1);}returnans;}// Driver codeletV=5;letedges=[[0,1],[1,4],[4,3],[4,2],[2,3]];letans=articulationPoints(V,edges);console.log(ans.join(" "));
Output
1 4
[Better Approach] - Recursive Tarjan's Algorithm - O(V + E) Time and O(V) Space
The idea is to use DFS to track how each node connects to its ancestors using discovery time and low values:
Discovery time (disc[]): when the node is first visited.
Low value (low[]): the earliest ancestor that the node's subtree can reach using a back edge.
For every child of a node, check whether its subtree can reach an ancestor without going through the current node.
If low[child] >= disc[node], the child cannot reach an ancestor without the current node.
Therefore, removing the current node disconnects that subtree, so the node is an articulation point.
By calculating and updating disc[] and low[] during DFS, we can find all articulation points in O(V + E) time.
Let's understand with an example:
For the vertex 3 (which is not the root), vertex 4 is the child of vertex 3. No vertex in the subtree rooted at vertex 4 has a back edge to one of ancestors of vertex 3. Thus on removal of vertex 3 and its associated edges the graph will get disconnected or the number of components in the graph will increase as the subtree rooted at vertex 4 will form a separate component. Hence vertex 3 is an articulation point.
Now consider the following graph:
Again the vertex 4 is the child of vertex 3. For the subtree rooted at vertex 4, vertex 7 in this subtree has a back edge to one of the ancestors of vertex 3 (which is vertex 1). Thus this subtree will not get disconnected on the removal of vertex 3 because of this back edge. Since there is no child v of vertex 3, such that subtree rooted at vertex v does not have a back edge to one of the ancestors of vertex 3. Hence vertex 3 is not an articulation point in this case.
Step by Step implementation:
Maintain these arrays and integers and perform a DFS traversal.
disc[]: Discovery time of each vertex during DFS.
low[]: The lowest discovery time reachable from the subtree rooted at that vertex (via tree or back edges).
parent: To keep track of each node’s parent in the DFS tree.
visited[]: To mark visited nodes.
Root Node Case:
For the root node of DFS (i.e., parent[u] == -1), check how many child DFS calls it makes.
If the root has two or more children, it is an articulation point
For any non-root node u, check all its adjacent nodes:
If v is an unvisited child, recur for v, and after returning update low[u] = min(low[u], low[v]) .
If low[v] >= disc[u], then u is an articulation point because v and its subtree cannot reach any ancestor of u, so removing u would disconnect v.
Back Edge Case
If v is already visited and is not the parent of u then It’s a back edge. Update low[u] = min(low[u], disc[v])
This helps bubble up the lowest reachable ancestor through a back edge.
After DFS traversal completes, all nodes marked as articulation points are stored in result array.
C++
#include<bits/stdc++.h>usingnamespacestd;voiddfs(intnode,intparent,vector<vector<int>>&adj,vector<int>&disc,vector<int>&low,vector<bool>&ap,int&timer){disc[node]=low[node]=timer++;intchildren=0;for(intneighbor:adj[node]){if(neighbor==parent)continue;if(disc[neighbor]==-1){children++;dfs(neighbor,node,adj,disc,low,ap,timer);// Update low valuelow[node]=min(low[node],low[neighbor]);// Check articulation point conditionif(parent!=-1&&low[neighbor]>=disc[node])ap[node]=true;}else{// Back edgelow[node]=min(low[node],disc[neighbor]);}}// Root is articulation point if it has more than one childif(parent==-1&&children>1)ap[node]=true;}vector<int>articulationPoints(intV,vector<vector<int>>&edges){vector<vector<int>>adj(V);// Build adjacency listfor(autoedge:edges){intu=edge[0];intv=edge[1];adj[u].push_back(v);adj[v].push_back(u);}vector<int>disc(V,-1);vector<int>low(V,-1);vector<bool>ap(V,false);inttimer=0;// Handle disconnected graphfor(inti=0;i<V;i++){if(disc[i]==-1)dfs(i,-1,adj,disc,low,ap,timer);}vector<int>ans;for(inti=0;i<V;i++){if(ap[i])ans.push_back(i);}if(ans.empty())ans.push_back(-1);returnans;}intmain(){intV=5;vector<vector<int>>edges={{0,1},{1,4},{4,3},{4,2},{2,3}};vector<int>ans=articulationPoints(V,edges);for(intx:ans)cout<<x<<" ";return0;}
Java
importjava.util.ArrayList;classGFG{staticvoiddfs(intnode,intparent,ArrayList<ArrayList<Integer>>adj,int[]disc,int[]low,boolean[]ap,int[]timer){disc[node]=low[node]=timer[0]++;intchildren=0;for(intneighbor:adj.get(node)){if(neighbor==parent)continue;if(disc[neighbor]==-1){children++;dfs(neighbor,node,adj,disc,low,ap,timer);// Update low valuelow[node]=Math.min(low[node],low[neighbor]);// Check articulation point conditionif(parent!=-1&&low[neighbor]>=disc[node])ap[node]=true;}else{// Back edgelow[node]=Math.min(low[node],disc[neighbor]);}}// Root is articulation point if it has more than one childif(parent==-1&&children>1)ap[node]=true;}staticArrayList<Integer>articulationPoints(intV,int[][]edges){ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<V;i++)adj.add(newArrayList<>());// Build adjacency listfor(int[]edge:edges){intu=edge[0];intv=edge[1];adj.get(u).add(v);adj.get(v).add(u);}int[]disc=newint[V];int[]low=newint[V];boolean[]ap=newboolean[V];for(inti=0;i<V;i++)disc[i]=-1;int[]timer={0};// Handle disconnected graphfor(inti=0;i<V;i++){if(disc[i]==-1)dfs(i,-1,adj,disc,low,ap,timer);}ArrayList<Integer>ans=newArrayList<>();for(inti=0;i<V;i++){if(ap[i])ans.add(i);}if(ans.isEmpty())ans.add(-1);returnans;}publicstaticvoidmain(String[]args){intV=5;int[][]edges={{0,1},{1,4},{4,3},{4,2},{2,3}};ArrayList<Integer>ans=articulationPoints(V,edges);for(intx:ans)System.out.print(x+" ");}}
Python
defdfs(node,parent,adj,disc,low,ap,timer):disc[node]=low[node]=timer[0]timer[0]+=1children=0forneighborinadj[node]:ifneighbor==parent:continueifdisc[neighbor]==-1:children+=1dfs(neighbor,node,adj,disc,low,ap,timer)# Update low valuelow[node]=min(low[node],low[neighbor])# Check articulation point conditionifparent!=-1andlow[neighbor]>=disc[node]:ap[node]=Trueelse:# Back edgelow[node]=min(low[node],disc[neighbor])# Root is articulation point if it has more than one childifparent==-1andchildren>1:ap[node]=TruedefarticulationPoints(V,edges):adj=[[]for_inrange(V)]# Build adjacency listforu,vinedges:adj[u].append(v)adj[v].append(u)disc=[-1]*Vlow=[-1]*Vap=[False]*Vtimer=[0]# Handle disconnected graphforiinrange(V):ifdisc[i]==-1:dfs(i,-1,adj,disc,low,ap,timer)ans=[]foriinrange(V):ifap[i]:ans.append(i)ifnotans:ans.append(-1)returnansif__name__=="__main__":V=5edges=[[0,1],[1,4],[4,3],[4,2],[2,3]]ans=articulationPoints(V,edges)print(*ans)
C#
usingSystem;usingSystem.Collections.Generic;classGFG{staticvoiddfs(intnode,intparent,List<List<int>>adj,int[]disc,int[]low,bool[]ap,refinttimer){disc[node]=low[node]=timer++;intchildren=0;foreach(intneighborinadj[node]){if(neighbor==parent)continue;if(disc[neighbor]==-1){children++;dfs(neighbor,node,adj,disc,low,ap,reftimer);// Update low valuelow[node]=Math.Min(low[node],low[neighbor]);// Check articulation point conditionif(parent!=-1&&low[neighbor]>=disc[node])ap[node]=true;}else{// Back edgelow[node]=Math.Min(low[node],disc[neighbor]);}}// Root is articulation point if it has more than one childif(parent==-1&&children>1)ap[node]=true;}staticList<int>articulationPoints(intV,List<List<int>>edges){List<List<int>>adj=newList<List<int>>();for(inti=0;i<V;i++)adj.Add(newList<int>());// Build adjacency listforeach(List<int>edgeinedges){intu=edge[0];intv=edge[1];adj[u].Add(v);adj[v].Add(u);}int[]disc=newint[V];int[]low=newint[V];bool[]ap=newbool[V];for(inti=0;i<V;i++)disc[i]=-1;inttimer=0;// Handle disconnected graphfor(inti=0;i<V;i++){if(disc[i]==-1)dfs(i,-1,adj,disc,low,ap,reftimer);}List<int>ans=newList<int>();for(inti=0;i<V;i++){if(ap[i])ans.Add(i);}if(ans.Count==0)ans.Add(-1);returnans;}staticvoidMain(){intV=5;List<List<int>>edges=newList<List<int>>{newList<int>{0,1},newList<int>{1,4},newList<int>{4,3},newList<int>{4,2},newList<int>{2,3}};List<int>ans=articulationPoints(V,edges);foreach(intxinans)Console.Write(x+" ");}}
JavaScript
functiondfs(node,parent,adj,disc,low,ap,timer){disc[node]=low[node]=timer.value++;letchildren=0;for(letneighborofadj[node]){if(neighbor===parent)continue;if(disc[neighbor]===-1){children++;dfs(neighbor,node,adj,disc,low,ap,timer);// Update low valuelow[node]=Math.min(low[node],low[neighbor]);// Check articulation point conditionif(parent!==-1&&low[neighbor]>=disc[node])ap[node]=true;}else{// Back edgelow[node]=Math.min(low[node],disc[neighbor]);}}// Root is articulation point if it has more than one childif(parent===-1&&children>1)ap[node]=true;}functionarticulationPoints(V,edges){letadj=Array.from({length:V},()=>[]);// Build adjacency listfor(let[u,v]ofedges){adj[u].push(v);adj[v].push(u);}letdisc=newArray(V).fill(-1);letlow=newArray(V).fill(-1);letap=newArray(V).fill(false);lettimer={value:0};// Handle disconnected graphfor(leti=0;i<V;i++){if(disc[i]===-1)dfs(i,-1,adj,disc,low,ap,timer);}letans=[];for(leti=0;i<V;i++){if(ap[i])ans.push(i);}if(ans.length===0)ans.push(-1);returnans;}// Driver codeletV=5;letedges=[[0,1],[1,4],[4,3],[4,2],[2,3]];letans=articulationPoints(V,edges);console.log(ans.join(" "));
Output
1 4
[Expected Approach] - Iterative Tarjan’s Algorithm - O(V + E) Time and O(V) Space
We use Tarjan’s algorithm with an explicit stack to manage the traversal state instead of relying on the system’s call stack. The logic remains the same that we maintain disc, low, parent, and childrenCount but we manually control how nodes are processed.
For each node, we store its current state, including which neighbor to visit next and whether the node is in the entering or exiting phase.
With this approach, we preserve the core idea of Tarjan’s algorithm while making it more suitable for large or deep graphs.
C++
#include<bits/stdc++.h>usingnamespacestd;vector<int>articulationPoints(intV,vector<vector<int>>&edges){vector<vector<int>>adj(V);// Build adjacency listfor(autoedge:edges){intu=edge[0];intv=edge[1];adj[u].push_back(v);adj[v].push_back(u);}vector<int>disc(V,-1);vector<int>low(V,-1);vector<int>parent(V,-1);vector<int>children(V,0);vector<bool>ap(V,false);inttimer=0;for(intstart=0;start<V;start++){if(disc[start]!=-1)continue;stack<pair<int,int>>st;disc[start]=low[start]=timer++;st.push({start,0});while(!st.empty()){intnode=st.top().first;intindex=st.top().second;if(index<adj[node].size()){intneighbor=adj[node][index];st.top().second++;if(neighbor==parent[node])continue;if(disc[neighbor]==-1){parent[neighbor]=node;children[node]++;disc[neighbor]=low[neighbor]=timer++;st.push({neighbor,0});}else{// Back edgelow[node]=min(low[node],disc[neighbor]);}}else{st.pop();// Update parent after child is completely processedif(parent[node]!=-1){intp=parent[node];low[p]=min(low[p],low[node]);// Parent must not be the DFS rootif(parent[p]!=-1&&low[node]>=disc[p]){ap[p]=true;}}else{// Root is articulation point only with 2+ childrenif(children[node]>1)ap[node]=true;}}}}vector<int>ans;for(inti=0;i<V;i++){if(ap[i])ans.push_back(i);}if(ans.empty())ans.push_back(-1);returnans;}intmain(){intV=5;vector<vector<int>>edges={{0,1},{1,4},{4,3},{4,2},{2,3}};vector<int>ans=articulationPoints(V,edges);for(intx:ans)cout<<x<<" ";return0;}
Java
importjava.util.ArrayList;importjava.util.Stack;classGFG{staticclassFrame{intnode;intindex;Frame(intnode,intindex){this.node=node;this.index=index;}}staticArrayList<Integer>articulationPoints(intV,int[][]edges){ArrayList<ArrayList<Integer>>adj=newArrayList<>();for(inti=0;i<V;i++)adj.add(newArrayList<>());// Build adjacency listfor(int[]edge:edges){intu=edge[0];intv=edge[1];adj.get(u).add(v);adj.get(v).add(u);}int[]disc=newint[V];int[]low=newint[V];int[]parent=newint[V];int[]children=newint[V];boolean[]ap=newboolean[V];for(inti=0;i<V;i++){disc[i]=-1;parent[i]=-1;}inttimer=0;for(intstart=0;start<V;start++){if(disc[start]!=-1)continue;Stack<Frame>st=newStack<>();disc[start]=low[start]=timer++;st.push(newFrame(start,0));while(!st.isEmpty()){Frameframe=st.peek();intnode=frame.node;if(frame.index<adj.get(node).size()){intneighbor=adj.get(node).get(frame.index);frame.index++;if(neighbor==parent[node])continue;if(disc[neighbor]==-1){parent[neighbor]=node;children[node]++;disc[neighbor]=low[neighbor]=timer++;st.push(newFrame(neighbor,0));}else{// Back edgelow[node]=Math.min(low[node],disc[neighbor]);}}else{st.pop();if(parent[node]!=-1){intp=parent[node];low[p]=Math.min(low[p],low[node]);// Parent must not be the rootif(parent[p]!=-1&&low[node]>=disc[p]){ap[p]=true;}}else{// Root conditionif(children[node]>1)ap[node]=true;}}}}ArrayList<Integer>ans=newArrayList<>();for(inti=0;i<V;i++){if(ap[i])ans.add(i);}if(ans.isEmpty())ans.add(-1);returnans;}publicstaticvoidmain(String[]args){intV=5;int[][]edges={{0,1},{1,4},{4,3},{4,2},{2,3}};ArrayList<Integer>ans=articulationPoints(V,edges);for(intx:ans)System.out.print(x+" ");}}
Python
defarticulationPoints(V,edges):adj=[[]for_inrange(V)]# Build adjacency listforu,vinedges:adj[u].append(v)adj[v].append(u)disc=[-1]*Vlow=[-1]*Vparent=[-1]*Vchildren=[0]*Vap=[False]*Vtimer=0forstartinrange(V):ifdisc[start]!=-1:continuedisc[start]=low[start]=timertimer+=1# node, next neighbor indexstack=[[start,0]]whilestack:node,index=stack[-1]ifindex<len(adj[node]):neighbor=adj[node][index]stack[-1][1]+=1ifneighbor==parent[node]:continueifdisc[neighbor]==-1:parent[neighbor]=nodechildren[node]+=1disc[neighbor]=low[neighbor]=timertimer+=1stack.append([neighbor,0])else:# Back edgelow[node]=min(low[node],disc[neighbor])else:stack.pop()ifparent[node]!=-1:p=parent[node]low[p]=min(low[p],low[node])# Parent must not be the rootifparent[p]!=-1and \
low[node]>=disc[p]:ap[p]=Trueelse:# Root conditionifchildren[node]>1:ap[node]=Trueans=[]foriinrange(V):ifap[i]:ans.append(i)ifnotans:ans.append(-1)returnansif__name__=="__main__":V=5edges=[[0,1],[1,4],[4,3],[4,2],[2,3]]ans=articulationPoints(V,edges)print(*ans)
C#
usingSystem;usingSystem.Collections.Generic;classGFG{classFrame{publicintnode;publicintindex;publicFrame(intnode,intindex){this.node=node;this.index=index;}}staticList<int>articulationPoints(intV,List<List<int>>edges){List<List<int>>adj=newList<List<int>>();for(inti=0;i<V;i++)adj.Add(newList<int>());// Build adjacency listforeach(List<int>edgeinedges){intu=edge[0];intv=edge[1];adj[u].Add(v);adj[v].Add(u);}int[]disc=newint[V];int[]low=newint[V];int[]parent=newint[V];int[]children=newint[V];bool[]ap=newbool[V];for(inti=0;i<V;i++){disc[i]=-1;parent[i]=-1;}inttimer=0;for(intstart=0;start<V;start++){if(disc[start]!=-1)continue;Stack<Frame>stack=newStack<Frame>();disc[start]=low[start]=timer++;stack.Push(newFrame(start,0));while(stack.Count>0){Frameframe=stack.Peek();intnode=frame.node;if(frame.index<adj[node].Count){intneighbor=adj[node][frame.index];frame.index++;if(neighbor==parent[node])continue;if(disc[neighbor]==-1){parent[neighbor]=node;children[node]++;disc[neighbor]=low[neighbor]=timer++;stack.Push(newFrame(neighbor,0));}else{// Back edgelow[node]=Math.Min(low[node],disc[neighbor]);}}else{stack.Pop();if(parent[node]!=-1){intp=parent[node];low[p]=Math.Min(low[p],low[node]);// Parent must not be the rootif(parent[p]!=-1&&low[node]>=disc[p]){ap[p]=true;}}else{// Root conditionif(children[node]>1)ap[node]=true;}}}}List<int>ans=newList<int>();for(inti=0;i<V;i++){if(ap[i])ans.Add(i);}if(ans.Count==0)ans.Add(-1);returnans;}staticvoidMain(){intV=5;List<List<int>>edges=newList<List<int>>{newList<int>{0,1},newList<int>{1,4},newList<int>{4,3},newList<int>{4,2},newList<int>{2,3}};List<int>ans=articulationPoints(V,edges);foreach(intxinans)Console.Write(x+" ");}}
JavaScript
classFrame{constructor(node,index){this.node=node;this.index=index;}}functionarticulationPoints(V,edges){letadj=Array.from({length:V},()=>[]);// Build adjacency listfor(let[u,v]ofedges){adj[u].push(v);adj[v].push(u);}letdisc=newArray(V).fill(-1);letlow=newArray(V).fill(-1);letparent=newArray(V).fill(-1);letchildren=newArray(V).fill(0);letap=newArray(V).fill(false);lettimer=0;for(letstart=0;start<V;start++){if(disc[start]!==-1)continue;letstack=[];disc[start]=low[start]=timer++;stack.push(newFrame(start,0));while(stack.length>0){letframe=stack[stack.length-1];letnode=frame.node;if(frame.index<adj[node].length){letneighbor=adj[node][frame.index];frame.index++;if(neighbor===parent[node])continue;if(disc[neighbor]===-1){parent[neighbor]=node;children[node]++;disc[neighbor]=low[neighbor]=timer++;stack.push(newFrame(neighbor,0));}else{// Back edgelow[node]=Math.min(low[node],disc[neighbor]);}}else{stack.pop();if(parent[node]!==-1){letp=parent[node];low[p]=Math.min(low[p],low[node]);// Parent must not be the rootif(parent[p]!==-1&&low[node]>=disc[p]){ap[p]=true;}}else{// Root conditionif(children[node]>1)ap[node]=true;}}}}letans=[];for(leti=0;i<V;i++){if(ap[i])ans.push(i);}if(ans.length===0)ans.push(-1);returnans;}// Driver codeletV=5;letedges=[[0,1],[1,4],[4,3],[4,2],[2,3]];letans=articulationPoints(V,edges);console.log(ans.join(" "));