Open In App

Check loop in array according to given constraints

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[0..n-1] of positive and negative numbers we need to find if there is a cycle in array with given rules of movements. If a number at an i index is positive, then move arr[i]%n forward steps, i.e., next index to visit is (i + arr[i])%n. Conversely, if it’s negative, move backward arr[i]%n steps i.e., next index to visit is (i – arr[i])%n. Here n is size of array. If value of arr[i]%n is zero, then it means no move from index i.

Examples: 

Input: arr[] = {2, -1, 1, 2, 2}
Output: Yes
Explanation: There is a loop in this array
because 0 moves to 2, 2 moves to 3, and 3
moves to 0.
Input : arr[] = {1, 1, 1, 1, 1, 1}
Output : Yes
Whole array forms a loop.
Input : arr[] = {1, 2}
Output : No
We move from 0 to index 1. From index
1, there is no move as 2%n is 0. Note that
n is 2.

Note that self loops are not considered a cycle. For example {0} is not cyclic.

The idea is to form a directed graph of array elements using given set of rules. While forming the graph we don’t make self loops as value arr[i]%n equals to 0 means no moves. Finally our task reduces to detecting cycle in a directed graph. For detecting cycle, we use DFS and in DFS if reach a node which is visited and recursion call stack, we say there is a cycle.

Implementation:

C++




// C++ program to check if a given array is cyclic or not
#include<bits/stdc++.h>
using namespace std;
 
// A simple Graph DFS based recursive function to check if
// there is cycle in graph with vertex v as root of DFS.
// Refer below article for details.
bool isCycleRec(int v, vector<int>adj[],
               vector<bool> &visited, vector<bool> &recur)
{
    visited[v] = true;
    recur[v] = true;
    for (int i=0; i<adj[v].size(); i++)
    {
        if (visited[adj[v][i]] == false)
        {
            if (isCycleRec(adj[v][i], adj, visited, recur))
                return true;
        }
 
        // There is a cycle if an adjacent is visited
        // and present in recursion call stack recur[]
        else if (visited[adj[v][i]] == true &&
                 recur[adj[v][i]] == true)
            return true;
    }
 
    recur[v] = false;
    return false;
}
 
// Returns true if arr[] has cycle
bool isCycle(int arr[], int n)
{
    // Create a graph using given moves in arr[]
    vector<int>adj[n];
    for (int i=0; i<n; i++)
      if (i != (i+arr[i]+n)%n)
        adj[i].push_back((i+arr[i]+n)%n);
 
    // Do DFS traversal of graph to detect cycle
    vector<bool> visited(n, false);
    vector<bool> recur(n, false);
    for (int i=0; i<n; i++)
        if (visited[i]==false)
            if (isCycleRec(i, adj, visited, recur))
                return true;
    return true;
}
 
// Driver code
int main(void)
{
    int arr[] = {2, -1, 1, 2, 2};
    int n = sizeof(arr)/sizeof(arr[0]);
    if (isCycle(arr, n))
        cout << "Yes"<<endl;
    else
        cout << "No"<<endl;
    return 0;
}


Java




// Java program to check if
// a given array is cyclic or not
import java.util.Vector;
 
class GFG
{
 
    // A simple Graph DFS based recursive function
    // to check if there is cycle in graph with
    // vertex v as root of DFS. Refer below article for details.
    static boolean isCycleRec(int v, Vector<Integer>[] adj,
                                     Vector<Boolean> visited,
                                     Vector<Boolean> recur)
    {
        visited.set(v, true);
        recur.set(v, true);
 
        for (int i = 0; i < adj[v].size(); i++)
        {
            if (visited.elementAt(adj[v].elementAt(i)) == false)
            {
                if (isCycleRec(adj[v].elementAt(i),
                               adj, visited, recur))
                    return true;
            }
 
            // There is a cycle if an adjacent is visited
            // and present in recursion call stack recur[]
            else if (visited.elementAt(adj[v].elementAt(i)) == true &&
                       recur.elementAt(adj[v].elementAt(i)) == true)
                return true;
        }
        recur.set(v, false);
        return false;
    }
 
    // Returns true if arr[] has cycle
    @SuppressWarnings("unchecked")
    static boolean isCycle(int[] arr, int n)
    {
 
        // Create a graph using given moves in arr[]
        Vector<Integer>[] adj = new Vector[n];
        for (int i = 0; i < n; i++)
            if (i != (i + arr[i] + n) % n &&
                          adj[i] != null)
                adj[i].add((i + arr[i] + n) % n);
 
        // Do DFS traversal of graph to detect cycle
        Vector<Boolean> visited = new Vector<>();
        for (int i = 0; i < n; i++)
            visited.add(true);
        Vector<Boolean> recur = new Vector<>();
        for (int i = 0; i < n; i++)
            recur.add(true);
 
        for (int i = 0; i < n; i++)
            if (visited.elementAt(i) == false)
                if (isCycleRec(i, adj, visited, recur))
                    return true;
        return true;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int[] arr = { 2, -1, 1, 2, 2 };
        int n = arr.length;
        if (isCycle(arr, n) == true)
            System.out.println("Yes");
        else
            System.out.println("No");
    }
}
 
// This code is contributed by sanjeev2552


Python3




# Python3 program to check if a
# given array is cyclic or not
 
# A simple Graph DFS based recursive
# function to check if there is cycle
# in graph with vertex v as root of DFS.
# Refer below article for details.
# https:#www.geeksforgeeks.org/detect-cycle-in-a-graph/
def isCycleRec(v, adj, visited, recur):
    visited[v] = True
    recur[v] = True
    for i in range(len(adj[v])):
        if (visited[adj[v][i]] == False):
            if (isCycleRec(adj[v][i], adj,
                               visited, recur)):
                return True
 
        # There is a cycle if an adjacent is visited
        # and present in recursion call stack recur[]
        else if (visited[adj[v][i]] == True and
                recur[adj[v][i]] == True):
            return True
 
    recur[v] = False
    return False
 
# Returns true if arr[] has cycle
def isCycle(arr, n):
     
    # Create a graph using given
    # moves in arr[]
    adj = [[] for i in range(n)]
    for i in range(n):
        if (i != (i + arr[i] + n) % n):
            adj[i].append((i + arr[i] + n) % n)
 
    # Do DFS traversal of graph
    # to detect cycle  
    visited = [False] * n
    recur = [False] * n
    for i in range(n):
        if (visited[i] == False):
            if (isCycleRec(i, adj,
                           visited, recur)):
                return True
    return True
 
# Driver code
if __name__ == '__main__':
 
    arr = [2, -1, 1, 2, 2]
    n = len(arr)
    if (isCycle(arr, n)):
        print("Yes")
    else:
        print("No")
 
# This code is contributed by PranchalK


C#




// C# program to check if
// a given array is cyclic or not
using System;
using System.Collections.Generic;
public class GFG
{
 
  // A simple Graph DFS based recursive function
  // to check if there is cycle in graph with
  // vertex v as root of DFS. Refer below article for details.
  static bool isCycleRec(int v, List<int>[] adj,
                         List<Boolean> visited,
                         List<Boolean> recur)
  {
    visited[v] = true;
    recur[v] =  true;
 
    for (int i = 0; i < adj[v].Count; i++)
    {
      if (visited[adj[v][i]] == false)
      {
        if (isCycleRec(adj[v][i],
                       adj, visited, recur))
          return true;
      }
 
      // There is a cycle if an adjacent is visited
      // and present in recursion call stack recur[]
      else if (visited[adj[v][i]] == true &&
               recur[adj[v][i]] == true)
        return true;
    }
    recur[v] = false;
    return false;
  }
 
  // Returns true if []arr has cycle
  static bool isCycle(int[] arr, int n)
  {
 
    // Create a graph using given moves in []arr
    List<int>[] adj = new List<int>[n];
    for (int i = 0; i < n; i++)
      if (i != (i + arr[i] + n) % n &&
          adj[i] != null)
        adj[i].Add((i + arr[i] + n) % n);
 
    // Do DFS traversal of graph to detect cycle
    List<Boolean> visited = new List<Boolean>();
    for (int i = 0; i < n; i++)
      visited.Add(true);
    List<Boolean> recur = new List<Boolean>();
    for (int i = 0; i < n; i++)
      recur.Add(true);
 
    for (int i = 0; i < n; i++)
      if (visited[i] == false)
        if (isCycleRec(i, adj, visited, recur))
          return true;
    return true;
  }
 
  // Driver Code
  public static void Main(String[] args)
  {
    int[] arr = { 2, -1, 1, 2, 2 };
    int n = arr.Length;
    if (isCycle(arr, n) == true)
      Console.WriteLine("Yes");
    else
      Console.WriteLine("No");
  }
}
 
// This code is contributed by aashish1995


Javascript




<script>
 
// JavaScript program to check if a given array is cyclic or not
 
 
// A simple Graph DFS based recursive function to check if
// there is cycle in graph with vertex v as root of DFS.
// Refer below article for details.
function isCycleRec(v, adj, visited, recur) {
    visited[v] = true;
    recur[v] = true;
    for (let i = 0; i < adj[v].length; i++) {
        if (visited[adj[v][i]] == false) {
            if (isCycleRec(adj[v][i], adj, visited, recur))
                return true;
        }
 
        // There is a cycle if an adjacent is visited
        // and present in recursion call stack recur[]
        else if (visited[adj[v][i]] == true &&
            recur[adj[v][i]] == true)
            return true;
    }
 
    recur[v] = false;
    return false;
}
 
// Returns true if arr[] has cycle
function isCycle(arr, n) {
    // Create a graph using given moves in arr[]
    let adj = new Array(n).fill(0).map(() => []);
    for (let i = 0; i < n; i++)
        if (i != (i + arr[i] + n) % n)
            adj[i].push((i + arr[i] + n) % n);
 
    // Do DFS traversal of graph to detect cycle
    let visited = new Array(n).fill(false);
    let recur = new Array(n).fill(false);
    for (let i = 0; i < n; i++)
        if (visited[i] == false)
            if (isCycleRec(i, adj, visited, recur))
                return true;
    return true;
}
 
// Driver code
 
let arr = [2, -1, 1, 2, 2];
let n = arr.length;
if (isCycle(arr, n))
    document.write("Yes" + "<br>");
else
    document.write("No" + "<br>");
     
</script>


Output

Yes








Approach#2: Using Floyd’s cycle finding algorithm

This approach defines a function named “check_loop” that takes an array as input. It checks for a loop in the array by using the Floyd’s cycle-finding algorithm. The function maintains two pointers, one moving faster than the other. If there is a loop, the faster pointer will eventually catch up to the slower pointer. The function returns True if a loop is found and False otherwise.

Algorithm

1. Initialize a set ‘visited’ to keep track of visited indices and a variable ‘curr’ to start at index 0.
2. While traversing the array using a loop:
a. If the current index is already in the ‘visited’ set, return True as it indicates the presence of a loop.
b. If the current element is 0 or the next index to move to is the same as the current index, return False as there is no loop.
c. Otherwise, add the current index to the ‘visited’ set and update the ‘curr’ variable to the next index according to the array.
3. If the loop completes without finding a loop, return False.

C++




#include <iostream>
#include <vector>
#include <unordered_set>
 
std::string checkLoop(const std::vector<int>& arr) {
    int n = arr.size();
    std::unordered_set<int> visited;
    int curr = 0;
 
    while (true) {
        if (visited.find(curr) != visited.end()) {
            return "yes";
        }
        if (arr[curr] == 0 || curr == (curr + arr[curr]) % n) {
            return "no";
        }
        visited.insert(curr);
        curr = (curr + arr[curr]) % n;
    }
}
 
int main() {
    std::vector<int> arr = {2, -1, 1, 2, 2};
    std::cout << checkLoop(arr) << std::endl;
 
    return 0;
}


Java




import java.util.HashSet;
import java.util.Set;
 
public class LoopChecker {
 
    // Function to check if there exists a loop in the array
    public static String checkLoop(int[] arr) {
        int n = arr.length;
        Set<Integer> visited = new HashSet<>(); // Set to track visited indices
        int curr = 0; // Start from index 0
 
        while (true) {
            if (visited.contains(curr)) {
                return "yes"; // If the current index has been visited, a loop is found
            }
            if (arr[curr] == 0 || curr == (curr + arr[curr]) % n) {
                return "no"; // If a zero is encountered or the next index
                             // leads back to the current index, no loop exists
            }
            visited.add(curr); // Mark the current index as visited
            curr = (curr + arr[curr]) % n; // Move to the next index based on the array
                                           // element's value
        }
    }
 
    public static void main(String[] args) {
        int[] arr = {2, -1, 1, 2, 2};
        String result = checkLoop(arr); // Check for a loop in the array
        System.out.println(result);
    }
}
 
// This code is contributed by akshitaguprzj3


Python3




def check_loop(arr):
    n = len(arr)
    visited = set()
    curr = 0
 
    while True:
        if curr in visited:
            return 'yes'
        if arr[curr] == 0 or curr == (curr + arr[curr]) % n:
            return 'no'
        visited.add(curr)
        curr = (curr + arr[curr]) % n
 
arr = [2, -1, 1, 2, 2]
print(check_loop(arr))


C#




using System;
using System.Collections.Generic;
 
public class LoopChecker
{
    // Function to check if there exists a loop in the array
    public static string CheckLoop(int[] arr)
    {
        int n = arr.Length;
        HashSet<int> visited = new HashSet<int>(); // Set to track visited indices
        int curr = 0; // Start from index 0
 
        while (true)
        {
            if (visited.Contains(curr))
            {
                return "yes"; // If the current index has been visited, a loop is found
            }
            if (arr[curr] == 0 || curr == (curr + arr[curr]) % n)
            {
                return "no"; // If a zero is encountered or the next index
                             // leads back to the current index, no loop exists
            }
            visited.Add(curr); // Mark the current index as visited
            curr = (curr + arr[curr]) % n; // Move to the next index based on the array
                                           // element's value
        }
    }
 
    public static void Main(string[] args)
    {
        int[] arr = { 2, -1, 1, 2, 2 };
        string result = CheckLoop(arr); // Check for a loop in the array
        Console.WriteLine(result);
    }
}


Javascript




function check_loop(arr) {
    const n = arr.length; // Get the length of the array
    const visited = new Set(); // Create a set to store visited indices
    let curr = 0; // Start from the first index
 
    while (true) {
        if (visited.has(curr)) {
            // If the current index is already visited, there is a loop
            return 'yes';
        }
 
        if (arr[curr] === 0 || curr === (curr + arr[curr]) % n) {
            // If the value at the current index is 0 or if we end up at the same index after adding the value,
            // there is no loop, and we cannot move forward.
            return 'no';
        }
 
        visited.add(curr); // Mark the current index as visited
        curr = (curr + arr[curr]) % n; // Move to the next index based on the value at the current index
    }
}
 
const arr = [2, -1, 1, 2, 2];
console.log(check_loop(arr));
// THIS CODE IS CONTRIBUTED BY KIRTI AGARWAL


Output

yes








Time Complexity: O(n), where n is the length of the array. We traverse the array at most twice – once to check if the current index is already visited, and once to update the ‘curr’ variable. Both these operations take O(n) time in the worst case.

Space Complexity: O(n), where n is the length of the array. We use a set ‘visited’ to keep track of visited indices, which can have at most n elements in the worst case if there is no loop. The ‘curr’ variable takes constant space.



Last Updated : 17 Oct, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads