Articulation Points (or Cut Vertices) in a Graph

Last Updated : 17 Oct, 2026

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.

Examples:

Input: V = 5, edges[][] = [[0, 1], [1, 4], [4, 3], [4, 2], [2, 3]]

1


Output: [1, 4]
Explanation: Removing vertex 1 or 4 disconnects the graph, as illustrated below:

2

Input: V = 4, edges[][] = [[0, 1], [0, 2]]
Output: [0]
Explanation: Removing the vertex 0 will increase the number of disconnected components to 3.

Try It Yourself
redirect icon

[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>
using namespace std;

void dfs(int node, vector<vector<int>>& adj, vector<bool>& visited) {
    visited[node] = true;

    for (int neighbor : adj[node]) {
        if (!visited[neighbor])
            dfs(neighbor, adj, visited);
    }
}

vector<int> articulationPoints(int V, vector<vector<int>>& edges) {
    vector<vector<int>> adj(V);

    // Build adjacency list
    for (auto edge : edges) {
        int u = edge[0];
        int v = edge[1];

        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    vector<int> ans;

    // Try removing every vertex
    for (int i = 0; i < V; i++) {
        vector<bool> visited(V, false);
        visited[i] = true;

        int components = 0;

        // Run DFS from each unvisited neighbor
        for (int neighbor : adj[i]) {
            if (!visited[neighbor]) {
                dfs(neighbor, adj, visited);
                components++;
            }
        }

        // More than one component means articulation point
        if (components > 1)
            ans.push_back(i);
    }

    if (ans.empty())
        ans.push_back(-1);

    return ans;
}

int main() {
    int V = 5;

    vector<vector<int>> edges = {
        {0, 1},
        {1, 4},
        {4, 3},
        {4, 2},
        {2, 3}
    };

    vector<int> ans = articulationPoints(V, edges);

    for (int x : ans)
        cout << x << " ";

    return 0;
}
Java
import java.util.ArrayList;

class GFG {

    static void dfs(int node, ArrayList<ArrayList<Integer>> adj,
                    boolean[] visited) {

        visited[node] = true;

        for (int neighbor : adj.get(node)) {
            if (!visited[neighbor])
                dfs(neighbor, adj, visited);
        }
    }

    static ArrayList<Integer> articulationPoints(
            int V, int[][] edges) {

        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();

        for (int i = 0; i < V; i++)
            adj.add(new ArrayList<>());

        // Build adjacency list
        for (int[] edge : edges) {
            int u = edge[0];
            int v = edge[1];

            adj.get(u).add(v);
            adj.get(v).add(u);
        }

        ArrayList<Integer> ans = new ArrayList<>();

        // Try removing every vertex
        for (int i = 0; i < V; i++) {
            boolean[] visited = new boolean[V];
            visited[i] = true;

            int components = 0;

            // Run DFS from each unvisited neighbor
            for (int neighbor : adj.get(i)) {
                if (!visited[neighbor]) {
                    dfs(neighbor, adj, visited);
                    components++;
                }
            }

            // More than one component means articulation point
            if (components > 1)
                ans.add(i);
        }

        if (ans.isEmpty())
            ans.add(-1);

        return ans;
    }

    public static void main(String[] args) {
        int V = 5;

        int[][] edges = {
            {0, 1},
            {1, 4},
            {4, 3},
            {4, 2},
            {2, 3}
        };

        ArrayList<Integer> ans = articulationPoints(V, edges);

        for (int x : ans)
            System.out.print(x + " ");
    }
}
Python
def dfs(node, adj, visited):
    visited[node] = True

    for neighbor in adj[node]:
        if not visited[neighbor]:
            dfs(neighbor, adj, visited)


def articulationPoints(V, edges):
    adj = [[] for _ in range(V)]

    # Build adjacency list
    for u, v in edges:
        adj[u].append(v)
        adj[v].append(u)

    ans = []

    # Try removing every vertex
    for i in range(V):
        visited = [False] * V
        visited[i] = True

        components = 0

        # Run DFS from each unvisited neighbor
        for neighbor in adj[i]:
            if not visited[neighbor]:
                dfs(neighbor, adj, visited)
                components += 1

        # More than one component means articulation point
        if components > 1:
            ans.append(i)

    if not ans:
        ans.append(-1)

    return ans


if __name__ == "__main__":
    V = 5

    edges = [
        [0, 1],
        [1, 4],
        [4, 3],
        [4, 2],
        [2, 3]
    ]

    ans = articulationPoints(V, edges)

    print(*ans)
C#
using System;
using System.Collections.Generic;

class GFG
{
    static void dfs(int node, List<List<int>> adj,
                    bool[] visited)
    {
        visited[node] = true;

        foreach (int neighbor in adj[node])
        {
            if (!visited[neighbor])
                dfs(neighbor, adj, visited);
        }
    }

    static List<int> articulationPoints(int V, List<List<int>> edges)
    {
        List<List<int>> adj = new List<List<int>>();

        for (int i = 0; i < V; i++)
            adj.Add(new List<int>());

        // Build adjacency list
        foreach (List<int> edge in edges)
        {
            int u = edge[0];
            int v = edge[1];

            adj[u].Add(v);
            adj[v].Add(u);
        }

        List<int> ans = new List<int>();

        // Try removing every vertex
        for (int i = 0; i < V; i++)
        {
            bool[] visited = new bool[V];
            visited[i] = true;

            int components = 0;

            // Run DFS from each unvisited neighbor
            foreach (int neighbor in adj[i])
            {
                if (!visited[neighbor])
                {
                    dfs(neighbor, adj, visited);
                    components++;
                }
            }

            // More than one component means articulation point
            if (components > 1)
                ans.Add(i);
        }

        if (ans.Count == 0)
            ans.Add(-1);

        return ans;
    }

    static void Main()
    {
        int V = 5;

        List<List<int>> edges = new List<List<int>>
        {
            new List<int> { 0, 1 },
            new List<int> { 1, 4 },
            new List<int> { 4, 3 },
            new List<int> { 4, 2 },
            new List<int> { 2, 3 }
        };

        List<int> ans = articulationPoints(V, edges);

        foreach (int x in ans)
            Console.Write(x + " ");
    }
}
JavaScript
function dfs(node, adj, visited) {
    visited[node] = true;

    for (let neighbor of adj[node]) {
        if (!visited[neighbor]) {
            dfs(neighbor, adj, visited);
        }
    }
}

function articulationPoints(V, edges) {
    let adj = Array.from({ length: V }, () => []);

    // Build adjacency list
    for (let [u, v] of edges) {
        adj[u].push(v);
        adj[v].push(u);
    }

    let ans = [];

    // Try removing every vertex
    for (let i = 0; i < V; i++) {
        let visited = new Array(V).fill(false);
        visited[i] = true;

        let components = 0;

        // Run DFS from each unvisited neighbor
        for (let neighbor of adj[i]) {
            if (!visited[neighbor]) {
                dfs(neighbor, adj, visited);
                components++;
            }
        }

        // More than one component means articulation point
        if (components > 1) {
            ans.push(i);
        }
    }

    if (ans.length === 0) {
        ans.push(-1);
    }

    return ans;
}

// Driver code
let V = 5;

let edges = [
    [0, 1],
    [1, 4],
    [4, 3],
    [4, 2],
    [2, 3]
];

let ans = 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:

example-1drawio

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:
Tree1drawio

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>
using namespace std;

void dfs(int node, int parent, vector<vector<int>>& adj,
         vector<int>& disc, vector<int>& low,
         vector<bool>& ap, int& timer)
{
    disc[node] = low[node] = timer++;
    int children = 0;

    for (int neighbor : adj[node])
    {
        if (neighbor == parent)
            continue;

        if (disc[neighbor] == -1)
        {
            children++;

            dfs(neighbor, node, adj, disc, low, ap, timer);

            // Update low value
            low[node] = min(low[node], low[neighbor]);

            // Check articulation point condition
            if (parent != -1 && low[neighbor] >= disc[node])
                ap[node] = true;
        }
        else
        {
            // Back edge
            low[node] = min(low[node], disc[neighbor]);
        }
    }

    // Root is articulation point if it has more than one child
    if (parent == -1 && children > 1)
        ap[node] = true;
}

vector<int> articulationPoints(int V, vector<vector<int>>& edges)
{
    vector<vector<int>> adj(V);

    // Build adjacency list
    for (auto edge : edges)
    {
        int u = edge[0];
        int v = 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);

    int timer = 0;

    // Handle disconnected graph
    for (int i = 0; i < V; i++)
    {
        if (disc[i] == -1)
            dfs(i, -1, adj, disc, low, ap, timer);
    }

    vector<int> ans;

    for (int i = 0; i < V; i++)
    {
        if (ap[i])
            ans.push_back(i);
    }

    if (ans.empty())
        ans.push_back(-1);

    return ans;
}

int main()
{
    int V = 5;

    vector<vector<int>> edges = {
        {0, 1},
        {1, 4},
        {4, 3},
        {4, 2},
        {2, 3}
    };

    vector<int> ans = articulationPoints(V, edges);

    for (int x : ans)
        cout << x << " ";

    return 0;
}
Java
import java.util.ArrayList;

class GFG {

    static void dfs(int node, int parent,
                    ArrayList<ArrayList<Integer>> adj,
                    int[] disc, int[] low,
                    boolean[] ap, int[] timer) {

        disc[node] = low[node] = timer[0]++;
        int children = 0;

        for (int neighbor : adj.get(node)) {

            if (neighbor == parent)
                continue;

            if (disc[neighbor] == -1) {
                children++;

                dfs(neighbor, node, adj, disc, low, ap, timer);

                // Update low value
                low[node] = Math.min(low[node], low[neighbor]);

                // Check articulation point condition
                if (parent != -1 && low[neighbor] >= disc[node])
                    ap[node] = true;
            }
            else {
                // Back edge
                low[node] = Math.min(low[node], disc[neighbor]);
            }
        }

        // Root is articulation point if it has more than one child
        if (parent == -1 && children > 1)
            ap[node] = true;
    }

    static ArrayList<Integer> articulationPoints(
            int V, int[][] edges) {

        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();

        for (int i = 0; i < V; i++)
            adj.add(new ArrayList<>());

        // Build adjacency list
        for (int[] edge : edges) {
            int u = edge[0];
            int v = edge[1];

            adj.get(u).add(v);
            adj.get(v).add(u);
        }

        int[] disc = new int[V];
        int[] low = new int[V];
        boolean[] ap = new boolean[V];

        for (int i = 0; i < V; i++)
            disc[i] = -1;

        int[] timer = {0};

        // Handle disconnected graph
        for (int i = 0; i < V; i++) {
            if (disc[i] == -1)
                dfs(i, -1, adj, disc, low, ap, timer);
        }

        ArrayList<Integer> ans = new ArrayList<>();

        for (int i = 0; i < V; i++) {
            if (ap[i])
                ans.add(i);
        }

        if (ans.isEmpty())
            ans.add(-1);

        return ans;
    }

    public static void main(String[] args) {

        int V = 5;

        int[][] edges = {
            {0, 1},
            {1, 4},
            {4, 3},
            {4, 2},
            {2, 3}
        };

        ArrayList<Integer> ans = articulationPoints(V, edges);

        for (int x : ans)
            System.out.print(x + " ");
    }
}
Python
def dfs(node, parent, adj, disc, low, ap, timer):
    disc[node] = low[node] = timer[0]
    timer[0] += 1

    children = 0

    for neighbor in adj[node]:

        if neighbor == parent:
            continue

        if disc[neighbor] == -1:
            children += 1

            dfs(neighbor, node, adj, disc, low, ap, timer)

            # Update low value
            low[node] = min(low[node], low[neighbor])

            # Check articulation point condition
            if parent != -1 and low[neighbor] >= disc[node]:
                ap[node] = True

        else:
            # Back edge
            low[node] = min(low[node], disc[neighbor])

    # Root is articulation point if it has more than one child
    if parent == -1 and children > 1:
        ap[node] = True


def articulationPoints(V, edges):
    adj = [[] for _ in range(V)]

    # Build adjacency list
    for u, v in edges:
        adj[u].append(v)
        adj[v].append(u)

    disc = [-1] * V
    low = [-1] * V
    ap = [False] * V

    timer = [0]

    # Handle disconnected graph
    for i in range(V):
        if disc[i] == -1:
            dfs(i, -1, adj, disc, low, ap, timer)

    ans = []

    for i in range(V):
        if ap[i]:
            ans.append(i)

    if not ans:
        ans.append(-1)

    return ans


if __name__ == "__main__":
    V = 5

    edges = [
        [0, 1],
        [1, 4],
        [4, 3],
        [4, 2],
        [2, 3]
    ]

    ans = articulationPoints(V, edges)

    print(*ans)
C#
using System;
using System.Collections.Generic;

class GFG
{
    static void dfs(int node, int parent,
                    List<List<int>> adj,
                    int[] disc, int[] low,
                    bool[] ap, ref int timer)
    {
        disc[node] = low[node] = timer++;
        int children = 0;

        foreach (int neighbor in adj[node])
        {
            if (neighbor == parent)
                continue;

            if (disc[neighbor] == -1)
            {
                children++;

                dfs(neighbor, node, adj, disc, low, ap, ref timer);

                // Update low value
                low[node] = Math.Min(low[node], low[neighbor]);

                // Check articulation point condition
                if (parent != -1 && low[neighbor] >= disc[node])
                    ap[node] = true;
            }
            else
            {
                // Back edge
                low[node] = Math.Min(low[node], disc[neighbor]);
            }
        }

        // Root is articulation point if it has more than one child
        if (parent == -1 && children > 1)
            ap[node] = true;
    }

    static List<int> articulationPoints(
        int V, List<List<int>> edges)
    {
        List<List<int>> adj = new List<List<int>>();

        for (int i = 0; i < V; i++)
            adj.Add(new List<int>());

        // Build adjacency list
        foreach (List<int> edge in edges)
        {
            int u = edge[0];
            int v = edge[1];

            adj[u].Add(v);
            adj[v].Add(u);
        }

        int[] disc = new int[V];
        int[] low = new int[V];
        bool[] ap = new bool[V];

        for (int i = 0; i < V; i++)
            disc[i] = -1;

        int timer = 0;

        // Handle disconnected graph
        for (int i = 0; i < V; i++)
        {
            if (disc[i] == -1)
                dfs(i, -1, adj, disc, low, ap, ref timer);
        }

        List<int> ans = new List<int>();

        for (int i = 0; i < V; i++)
        {
            if (ap[i])
                ans.Add(i);
        }

        if (ans.Count == 0)
            ans.Add(-1);

        return ans;
    }

    static void Main()
    {
        int V = 5;

        List<List<int>> edges = new List<List<int>>
        {
            new List<int> { 0, 1 },
            new List<int> { 1, 4 },
            new List<int> { 4, 3 },
            new List<int> { 4, 2 },
            new List<int> { 2, 3 }
        };

        List<int> ans = articulationPoints(V, edges);

        foreach (int x in ans)
            Console.Write(x + " ");
    }
}
JavaScript
function dfs(node, parent, adj, disc, low, ap, timer) {
    disc[node] = low[node] = timer.value++;
    let children = 0;

    for (let neighbor of adj[node]) {

        if (neighbor === parent)
            continue;

        if (disc[neighbor] === -1) {
            children++;

            dfs(neighbor, node, adj, disc, low, ap, timer);

            // Update low value
            low[node] = Math.min(low[node], low[neighbor]);

            // Check articulation point condition
            if (parent !== -1 && low[neighbor] >= disc[node])
                ap[node] = true;
        }
        else {
            // Back edge
            low[node] = Math.min(low[node], disc[neighbor]);
        }
    }

    // Root is articulation point if it has more than one child
    if (parent === -1 && children > 1)
        ap[node] = true;
}

function articulationPoints(V, edges) {
    let adj = Array.from({ length: V }, () => []);

    // Build adjacency list
    for (let [u, v] of edges) {
        adj[u].push(v);
        adj[v].push(u);
    }

    let disc = new Array(V).fill(-1);
    let low = new Array(V).fill(-1);
    let ap = new Array(V).fill(false);

    let timer = { value: 0 };

    // Handle disconnected graph
    for (let i = 0; i < V; i++) {
        if (disc[i] === -1)
            dfs(i, -1, adj, disc, low, ap, timer);
    }

    let ans = [];

    for (let i = 0; i < V; i++) {
        if (ap[i])
            ans.push(i);
    }

    if (ans.length === 0)
        ans.push(-1);

    return ans;
}

// Driver code
let V = 5;

let edges = [
    [0, 1],
    [1, 4],
    [4, 3],
    [4, 2],
    [2, 3]
];

let ans = 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>
using namespace std;

vector<int> articulationPoints(int V, vector<vector<int>>& edges)
{
    vector<vector<int>> adj(V);

    // Build adjacency list
    for (auto edge : edges)
    {
        int u = edge[0];
        int v = 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);

    int timer = 0;

    for (int start = 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())
        {
            int node = st.top().first;
            int index = st.top().second;

            if (index < adj[node].size())
            {
                int neighbor = 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 edge
                    low[node] = min(low[node], disc[neighbor]);
                }
            }
            else
            {
                st.pop();

                // Update parent after child is completely processed
                if (parent[node] != -1)
                {
                    int p = parent[node];

                    low[p] = min(low[p], low[node]);

                    // Parent must not be the DFS root
                    if (parent[p] != -1 &&
                        low[node] >= disc[p])
                    {
                        ap[p] = true;
                    }
                }
                else
                {
                    // Root is articulation point only with 2+ children
                    if (children[node] > 1)
                        ap[node] = true;
                }
            }
        }
    }

    vector<int> ans;

    for (int i = 0; i < V; i++)
    {
        if (ap[i])
            ans.push_back(i);
    }

    if (ans.empty())
        ans.push_back(-1);

    return ans;
}

int main()
{
    int V = 5;

    vector<vector<int>> edges = {
        {0, 1},
        {1, 4},
        {4, 3},
        {4, 2},
        {2, 3}
    };

    vector<int> ans = articulationPoints(V, edges);

    for (int x : ans)
        cout << x << " ";

    return 0;
}
Java
import java.util.ArrayList;
import java.util.Stack;

class GFG {

    static class Frame {
        int node;
        int index;

        Frame(int node, int index) {
            this.node = node;
            this.index = index;
        }
    }

    static ArrayList<Integer> articulationPoints(
            int V, int[][] edges) {

        ArrayList<ArrayList<Integer>> adj = new ArrayList<>();

        for (int i = 0; i < V; i++)
            adj.add(new ArrayList<>());

        // Build adjacency list
        for (int[] edge : edges) {
            int u = edge[0];
            int v = edge[1];

            adj.get(u).add(v);
            adj.get(v).add(u);
        }

        int[] disc = new int[V];
        int[] low = new int[V];
        int[] parent = new int[V];
        int[] children = new int[V];
        boolean[] ap = new boolean[V];

        for (int i = 0; i < V; i++) {
            disc[i] = -1;
            parent[i] = -1;
        }

        int timer = 0;

        for (int start = 0; start < V; start++) {

            if (disc[start] != -1)
                continue;

            Stack<Frame> st = new Stack<>();

            disc[start] = low[start] = timer++;
            st.push(new Frame(start, 0));

            while (!st.isEmpty()) {

                Frame frame = st.peek();
                int node = frame.node;

                if (frame.index < adj.get(node).size()) {

                    int neighbor = 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(new Frame(neighbor, 0));
                    }
                    else {
                        // Back edge
                        low[node] = Math.min(
                                low[node], disc[neighbor]);
                    }
                }
                else {

                    st.pop();

                    if (parent[node] != -1) {

                        int p = parent[node];

                        low[p] = Math.min(
                                low[p], low[node]);

                        // Parent must not be the root
                        if (parent[p] != -1 &&
                            low[node] >= disc[p]) {

                            ap[p] = true;
                        }
                    }
                    else {
                        // Root condition
                        if (children[node] > 1)
                            ap[node] = true;
                    }
                }
            }
        }

        ArrayList<Integer> ans = new ArrayList<>();

        for (int i = 0; i < V; i++) {
            if (ap[i])
                ans.add(i);
        }

        if (ans.isEmpty())
            ans.add(-1);

        return ans;
    }

    public static void main(String[] args) {

        int V = 5;

        int[][] edges = {
            {0, 1},
            {1, 4},
            {4, 3},
            {4, 2},
            {2, 3}
        };

        ArrayList<Integer> ans =
                articulationPoints(V, edges);

        for (int x : ans)
            System.out.print(x + " ");
    }
}
Python
def articulationPoints(V, edges):
    adj = [[] for _ in range(V)]

    # Build adjacency list
    for u, v in edges:
        adj[u].append(v)
        adj[v].append(u)

    disc = [-1] * V
    low = [-1] * V
    parent = [-1] * V
    children = [0] * V
    ap = [False] * V

    timer = 0

    for start in range(V):

        if disc[start] != -1:
            continue

        disc[start] = low[start] = timer
        timer += 1

        # node, next neighbor index
        stack = [[start, 0]]

        while stack:

            node, index = stack[-1]

            if index < len(adj[node]):

                neighbor = adj[node][index]
                stack[-1][1] += 1

                if neighbor == parent[node]:
                    continue

                if disc[neighbor] == -1:

                    parent[neighbor] = node
                    children[node] += 1

                    disc[neighbor] = low[neighbor] = timer
                    timer += 1

                    stack.append([neighbor, 0])

                else:
                    # Back edge
                    low[node] = min(
                        low[node], disc[neighbor])

            else:

                stack.pop()

                if parent[node] != -1:

                    p = parent[node]

                    low[p] = min(low[p], low[node])

                    # Parent must not be the root
                    if parent[p] != -1 and \
                       low[node] >= disc[p]:
                        ap[p] = True

                else:
                    # Root condition
                    if children[node] > 1:
                        ap[node] = True

    ans = []

    for i in range(V):
        if ap[i]:
            ans.append(i)

    if not ans:
        ans.append(-1)

    return ans


if __name__ == "__main__":
    V = 5

    edges = [
        [0, 1],
        [1, 4],
        [4, 3],
        [4, 2],
        [2, 3]
    ]

    ans = articulationPoints(V, edges)

    print(*ans)
C#
using System;
using System.Collections.Generic;

class GFG
{
    class Frame
    {
        public int node;
        public int index;

        public Frame(int node, int index)
        {
            this.node = node;
            this.index = index;
        }
    }

    static List<int> articulationPoints(
        int V, List<List<int>> edges)
    {
        List<List<int>> adj = new List<List<int>>();

        for (int i = 0; i < V; i++)
            adj.Add(new List<int>());

        // Build adjacency list
        foreach (List<int> edge in edges)
        {
            int u = edge[0];
            int v = edge[1];

            adj[u].Add(v);
            adj[v].Add(u);
        }

        int[] disc = new int[V];
        int[] low = new int[V];
        int[] parent = new int[V];
        int[] children = new int[V];
        bool[] ap = new bool[V];

        for (int i = 0; i < V; i++)
        {
            disc[i] = -1;
            parent[i] = -1;
        }

        int timer = 0;

        for (int start = 0; start < V; start++)
        {
            if (disc[start] != -1)
                continue;

            Stack<Frame> stack = new Stack<Frame>();

            disc[start] = low[start] = timer++;
            stack.Push(new Frame(start, 0));

            while (stack.Count > 0)
            {
                Frame frame = stack.Peek();
                int node = frame.node;

                if (frame.index < adj[node].Count)
                {
                    int neighbor = 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(new Frame(neighbor, 0));
                    }
                    else
                    {
                        // Back edge
                        low[node] = Math.Min(
                            low[node], disc[neighbor]);
                    }
                }
                else
                {
                    stack.Pop();

                    if (parent[node] != -1)
                    {
                        int p = parent[node];

                        low[p] = Math.Min(
                            low[p], low[node]);

                        // Parent must not be the root
                        if (parent[p] != -1 &&
                            low[node] >= disc[p])
                        {
                            ap[p] = true;
                        }
                    }
                    else
                    {
                        // Root condition
                        if (children[node] > 1)
                            ap[node] = true;
                    }
                }
            }
        }

        List<int> ans = new List<int>();

        for (int i = 0; i < V; i++)
        {
            if (ap[i])
                ans.Add(i);
        }

        if (ans.Count == 0)
            ans.Add(-1);

        return ans;
    }

    static void Main()
    {
        int V = 5;

        List<List<int>> edges = new List<List<int>>
        {
            new List<int> { 0, 1 },
            new List<int> { 1, 4 },
            new List<int> { 4, 3 },
            new List<int> { 4, 2 },
            new List<int> { 2, 3 }
        };

        List<int> ans = articulationPoints(V, edges);

        foreach (int x in ans)
            Console.Write(x + " ");
    }
}
JavaScript
class Frame {
    constructor(node, index) {
        this.node = node;
        this.index = index;
    }
}

function articulationPoints(V, edges) {
    let adj = Array.from({ length: V }, () => []);

    // Build adjacency list
    for (let [u, v] of edges) {
        adj[u].push(v);
        adj[v].push(u);
    }

    let disc = new Array(V).fill(-1);
    let low = new Array(V).fill(-1);
    let parent = new Array(V).fill(-1);
    let children = new Array(V).fill(0);
    let ap = new Array(V).fill(false);

    let timer = 0;

    for (let start = 0; start < V; start++) {

        if (disc[start] !== -1)
            continue;

        let stack = [];

        disc[start] = low[start] = timer++;

        stack.push(new Frame(start, 0));

        while (stack.length > 0) {

            let frame = stack[stack.length - 1];
            let node = frame.node;

            if (frame.index < adj[node].length) {

                let neighbor = 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(new Frame(neighbor, 0));
                }
                else {
                    // Back edge
                    low[node] = Math.min(
                        low[node], disc[neighbor]);
                }
            }
            else {

                stack.pop();

                if (parent[node] !== -1) {

                    let p = parent[node];

                    low[p] = Math.min(
                        low[p], low[node]);

                    // Parent must not be the root
                    if (parent[p] !== -1 &&
                        low[node] >= disc[p]) {

                        ap[p] = true;
                    }
                }
                else {
                    // Root condition
                    if (children[node] > 1)
                        ap[node] = true;
                }
            }
        }
    }

    let ans = [];

    for (let i = 0; i < V; i++) {
        if (ap[i])
            ans.push(i);
    }

    if (ans.length === 0)
        ans.push(-1);

    return ans;
}

// Driver code
let V = 5;

let edges = [
    [0, 1],
    [1, 4],
    [4, 3],
    [4, 2],
    [2, 3]
];

let ans = articulationPoints(V, edges);

console.log(ans.join(" "));

Output
1 4 
Comment