Open In App

Find if an array of strings can be chained to form a circle

Last Updated : 19 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an array of strings, the task is to find if the given strings can be chained to form a circle. A string X can be put before another string Y in circle if the last character of X is same as first character of Y.

Examples: 

Input: arr[] = [“geek”, “king”]
Output: Yes, the given strings can be chained.
Explanation: Note that the last character of first string is same
as first character of second string and vice versa is also true.

Input: arr[] = [“aaa”, “bbb”, “baa”, “aab”]
Output: Yes, the given strings can be chained.
Explanation: The strings can be chained as “aaa”, “aab”, “bbb” and “baa”

Input: arr[] = [“aaa”]
Output: Yes

Input: arr[] = [“aaa”, “bbb”]
Output: No

Approach:

The idea is to create a directed graph of all characters and then find if there is an eulerian circuit in the graph or not.  If there is an eulerian circuit, then chain can be formed, otherwise not. 

Note that a directed graph has eulerian circuit only if in degree and out degree of every vertex is same, and all non-zero degree vertices form a single strongly connected component.

We solve this problem by treating this as a graph problem, where vertices will be the first and last character of strings, and we will draw an edge between two vertices if they are the first and last character of the same string, so a number of edges in the graph will be same as the number of strings in the array.

Step by step approach:

  1. Create a directed graph where each node represents a letter (a-z) and edges connect first and last letters of words.
  2. For each string, add an edge from its first character to its last character.
  3. Check if the graph is strongly connected (can reach all nodes with non-zero degree from any node).
  4. Verify each node has equal in-degree and out-degree (necessary condition for Eulerian cycle).
  5. If both conditions are met, the strings can be chained in a circle.
C++
// C++ program to Find if an array of 
// strings can be chained to form a circle 
#include <iostream>
#include <vector>
using namespace std;

class Graph {
private:
    int V;                  
    vector<vector<int>> adj;  
    vector<int> in;         
    
    // Function to do DFS starting from v
    void dfsUtil(int v, vector<bool>& visited) {
        visited[v] = true;
        for (auto i = adj[v].begin(); i != adj[v].end(); ++i)
            if (!visited[*i])
                dfsUtil(*i, visited);
    }
    
    // Check if all non-zero degree vertices are strongly connected
    bool isStronglyConnected() {
        
        // Mark all vertices as not visited for first DFS
        vector<bool> visited(V, false);
        
        // Find the first vertex with non-zero degree
        int n;
        for (n = 0; n < V; n++)
            if (adj[n].size() > 0)
                break;
                
        // If no edges exist, return true
        if (n == V)
            return true;
        
        // Do DFS traversal starting from
        // first non-zero degree vertex
        dfsUtil(n, visited);
        
        // Check if all vertices with 
        // non-zero degrees are visited
        for (int i = 0; i < V; i++)
            if (adj[i].size() > 0 && !visited[i])
                return false;
        
        // Create a reversed graph
        Graph gr(V);
        for (int v = 0; v < V; v++) {
            for (auto i = adj[v].begin(); i != adj[v].end(); ++i) {
                gr.adj[*i].push_back(v);
                (gr.in[v])++;
            }
        }
        
        // Mark all vertices as not visited for second DFS
        fill(visited.begin(), visited.end(), false);
        
        // Do DFS for reversed graph starting from same vertex
        gr.dfsUtil(n, visited);
        
        // Check if all vertices with non-zero
        // degrees are visited in second DFS
        for (int i = 0; i < V; i++)
            if (adj[i].size() > 0 && !visited[i])
                return false;
                
        return true;
    }
    
public:
    Graph(int V) {
        this->V = V;
        adj.resize(V);
        in.resize(V, 0);
    }
    
    // Function to add an edge to graph
    void addEdge(int v, int w) {
        adj[v].push_back(w);
        in[w]++;
    }
    
    // Check if the directed graph has an Eulerian cycle
    bool hasEulerianCycle() {
        
        // Check if all non-zero degree
        // vertices are strongly connected
        if (!isStronglyConnected())
            return false;
        
        // Check if in-degree and out-degree 
        // of every vertex is the same
        for (int i = 0; i < V; i++)
            if (adj[i].size() != in[i])
                return false;
                
        return true;
    }
};

// Function to check if strings can be 
// chained to form a circle
bool isCircle(vector<string> &arr) {
    
    // Create a graph with 26 vertices (a to z)
    Graph g(26);
    
    // Create an edge from first character 
    // to last character of every string.
    for (string &s : arr) {
        if (!s.empty()) {
            g.addEdge(s[0] - 'a', s[s.length() - 1] - 'a');
        }
    }
    
    // The strings can be chained if there
    // is an Eulerian cycle in the graph
    return g.hasEulerianCycle();
}

int main() {
    vector<string> arr3 = {"ab" , "bc", "cd", "da"};
    cout << (isCircle(arr3) ? "Yes" : "No");
    
    return 0;
}
Java
// Java program to Find if an array of 
// strings can be chained to form a circle 
import java.util.*;

class Graph {
    int V;
    ArrayList<Integer>[] adj;
    int[] in;

    Graph(int V) {
        this.V = V;
        adj = new ArrayList[V];
        in = new int[V];
        for (int i = 0; i < V; i++) {
            adj[i] = new ArrayList<>();
        }
    }

    // Function to add an edge to graph
    static void addEdge(Graph g, int v, int w) {
        g.adj[v].add(w);
        g.in[w]++;
    }

    // Function to do DFS starting from v
    static void dfsUtil(Graph g, int v, boolean[] visited) {
        visited[v] = true;
        for (int i : g.adj[v]) {
            if (!visited[i])
                dfsUtil(g, i, visited);
        }
    }

    // Check if all non-zero degree vertices are strongly connected
    static boolean isStronglyConnected(Graph g) {
        boolean[] visited = new boolean[g.V];

        int n;
        for (n = 0; n < g.V; n++)
            if (g.adj[n].size() > 0)
                break;

        if (n == g.V)
            return true;

        dfsUtil(g, n, visited);

        for (int i = 0; i < g.V; i++)
            if (g.adj[i].size() > 0 && !visited[i])
                return false;

        Graph gr = new Graph(g.V);
        for (int v = 0; v < g.V; v++) {
            for (int i : g.adj[v]) {
                gr.adj[i].add(v);
                gr.in[v]++;
            }
        }

        Arrays.fill(visited, false);
        dfsUtil(gr, n, visited);

        for (int i = 0; i < g.V; i++)
            if (g.adj[i].size() > 0 && !visited[i])
                return false;

        return true;
    }

    // Check if the directed graph has an Eulerian cycle
    static boolean hasEulerianCycle(Graph g) {
        if (!isStronglyConnected(g))
            return false;

        for (int i = 0; i < g.V; i++)
            if (g.adj[i].size() != g.in[i])
                return false;

        return true;
    }
}

class GfG {

    // Function to check if strings can be 
    // chained to form a circle
    static int isCircle(String[] arr) {
        Graph g = new Graph(26);

        for (String s : arr) {
            if (!s.isEmpty()) {
                Graph.addEdge(g, s.charAt(0) - 'a', s.charAt(s.length() - 1) - 'a');
            }
        }

        return Graph.hasEulerianCycle(g)?1:0;
    }

    public static void main(String[] args) {
        String[] arr3 = {"ab", "bc", "cd", "da"};
        System.out.println(isCircle(arr3) == 1 ? "Yes" : "No");
    }
}
Python
# Python program to Find if an array of 
# strings can be chained to form a circle 

# Function to check if strings can be 
# chained to form a circle
def isCircle(arr):
    
    # Create a graph with 26 vertices (a to z)
    g = Graph(26)
    
    # Create an edge from first character 
    # to last character of every string.
    for s in arr:
        if s:
            g.addEdge(ord(s[0]) - ord('a'), ord(s[-1]) - ord('a'))
    
    # The strings can be chained if there
    # is an Eulerian cycle in the graph
    return 1 if g.hasEulerianCycle() else 0


class Graph:
    def __init__(self, V):
        self.V = V
        self.adj = [[] for _ in range(V)]
        self.inDegree = [0] * V

    # Function to add an edge to graph
    def addEdge(self, v, w):
        self.adj[v].append(w)
        self.inDegree[w] += 1

    # Function to do DFS starting from v
    def dfsUtil(self, v, visited):
        visited[v] = True
        for i in self.adj[v]:
            if not visited[i]:
                self.dfsUtil(i, visited)

    # Check if all non-zero degree vertices are strongly connected
    def isStronglyConnected(self):
        visited = [False] * self.V
        n = 0
        while n < self.V and not self.adj[n]:
            n += 1
        if n == self.V:
            return True

        self.dfsUtil(n, visited)
        for i in range(self.V):
            if self.adj[i] and not visited[i]:
                return False

        gr = Graph(self.V)
        for v in range(self.V):
            for i in self.adj[v]:
                gr.adj[i].append(v)
                gr.inDegree[v] += 1

        visited = [False] * self.V
        gr.dfsUtil(n, visited)
        for i in range(self.V):
            if self.adj[i] and not visited[i]:
                return False

        return True

    # Check if the directed graph has an Eulerian cycle
    def hasEulerianCycle(self):
        if not self.isStronglyConnected():
            return False
        for i in range(self.V):
            if len(self.adj[i]) != self.inDegree[i]:
                return False
        return True


if __name__ == "__main__":
    arr3 = ["ab", "bc", "cd", "da"]
    print("Yes" if isCircle(arr3) == 1 else "No")
C#
// C# program to Find if an array of 
// strings can be chained to form a circle 
using System;
using System.Collections.Generic;

class Graph {
    public int V;
    public List<int>[] adj;
    public int[] inDegree;

    public Graph(int V) {
        this.V = V;
        adj = new List<int>[V];
        for (int i = 0; i < V; i++)
            adj[i] = new List<int>();
        inDegree = new int[V];
    }

    public void addEdge(int v, int w) {
        adj[v].Add(w);
        inDegree[w]++;
    }

    public void dfsUtil(int v, bool[] visited) {
        visited[v] = true;
        foreach (int i in adj[v]) {
            if (!visited[i])
                dfsUtil(i, visited);
        }
    }

    public bool isStronglyConnected() {
        bool[] visited = new bool[V];
        int n = 0;
        while (n < V && adj[n].Count == 0)
            n++;
        if (n == V)
            return true;

        dfsUtil(n, visited);
        for (int i = 0; i < V; i++)
            if (adj[i].Count > 0 && !visited[i])
                return false;

        Graph gr = new Graph(V);
        for (int v = 0; v < V; v++) {
            foreach (int i in adj[v]) {
                gr.adj[i].Add(v);
                gr.inDegree[v]++;
            }
        }

        visited = new bool[V];
        gr.dfsUtil(n, visited);
        for (int i = 0; i < V; i++)
            if (adj[i].Count > 0 && !visited[i])
                return false;

        return true;
    }

    public bool hasEulerianCycle() {
        if (!isStronglyConnected())
            return false;
        for (int i = 0; i < V; i++)
            if (adj[i].Count != inDegree[i])
                return false;
        return true;
    }
}

class GfG {
    static int isCircle(string[] arr) {
        Graph g = new Graph(26);
        foreach (string s in arr) {
            if (s.Length > 0)
                g.addEdge(s[0] - 'a', s[s.Length - 1] - 'a');
        }
        return g.hasEulerianCycle() ? 1:0;
    }

    static void Main() {
        string[] arr3 = { "ab", "bc", "cd", "da" };
        Console.WriteLine(isCircle(arr3) == 1 ? "Yes" : "No");
    }
}
JavaScript
// JavaScript program to Find if an array of 
// strings can be chained to form a circle 

class Graph {
    constructor(V) {
        this.V = V;
        this.adj = Array.from({ length: V }, () => []);
        this.in = new Array(V).fill(0);
    }

    // Function to add an edge to graph
    addEdge(v, w) {
        this.adj[v].push(w);
        this.in[w]++;
    }

    // Function to do DFS starting from v
    dfsUtil(v, visited) {
        visited[v] = true;
        for (let i of this.adj[v]) {
            if (!visited[i]) {
                this.dfsUtil(i, visited);
            }
        }
    }

    // Check if all non-zero degree vertices are strongly connected
    isStronglyConnected() {
        let visited = new Array(this.V).fill(false);
        let n = 0;
        while (n < this.V && this.adj[n].length === 0)
            n++;
        if (n === this.V)
            return true;

        this.dfsUtil(n, visited);
        for (let i = 0; i < this.V; i++) {
            if (this.adj[i].length > 0 && !visited[i])
                return false;
        }

        let gr = new Graph(this.V);
        for (let v = 0; v < this.V; v++) {
            for (let i of this.adj[v]) {
                gr.adj[i].push(v);
                gr.in[v]++;
            }
        }

        visited.fill(false);
        gr.dfsUtil(n, visited);
        for (let i = 0; i < this.V; i++) {
            if (this.adj[i].length > 0 && !visited[i])
                return false;
        }

        return true;
    }

    // Check if the directed graph has an Eulerian cycle
    hasEulerianCycle() {
        if (!this.isStronglyConnected())
            return false;
        for (let i = 0; i < this.V; i++) {
            if (this.adj[i].length !== this.in[i])
                return false;
        }
        return true;
    }
}

// Function to check if strings can be 
// chained to form a circle
function isCircle(arr) {
    let g = new Graph(26);
    for (let s of arr) {
        if (s.length > 0) {
            g.addEdge(s.charCodeAt(0) - 97, s.charCodeAt(s.length - 1) - 97);
        }
    }
    return g.hasEulerianCycle()?1:0;
}

let arr3 = ["ab", "bc", "cd", "da"];
console.log(isCircle(arr3) === 1 ? "Yes" : "No");

Output
Yes

Time Complexity: O(n)
Auxiliary space:  O(n)

Related Article:



Next Article
Practice Tags :

Similar Reads