Check loop in array according to given constraints
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++
#include<bits/stdc++.h>
using namespace std;
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 ;
}
else if (visited[adj[v][i]] == true &&
recur[adj[v][i]] == true )
return true ;
}
recur[v] = false ;
return false ;
}
bool isCycle( int arr[], int n)
{
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);
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 ;
}
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
import java.util.Vector;
class GFG
{
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 ;
}
else if (visited.elementAt(adj[v].elementAt(i)) == true &&
recur.elementAt(adj[v].elementAt(i)) == true )
return true ;
}
recur.set(v, false );
return false ;
}
@SuppressWarnings ( "unchecked" )
static boolean isCycle( int [] arr, int n)
{
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);
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 ;
}
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" );
}
}
|
Python3
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
else if (visited[adj[v][i]] = = True and
recur[adj[v][i]] = = True ):
return True
recur[v] = False
return False
def isCycle(arr, n):
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)
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
if __name__ = = '__main__' :
arr = [ 2 , - 1 , 1 , 2 , 2 ]
n = len (arr)
if (isCycle(arr, n)):
print ( "Yes" )
else :
print ( "No" )
|
C#
using System;
using System.Collections.Generic;
public class GFG
{
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 ;
}
else if (visited[adj[v][i]] == true &&
recur[adj[v][i]] == true )
return true ;
}
recur[v] = false ;
return false ;
}
static bool isCycle( int [] arr, int n)
{
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);
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 ;
}
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" );
}
}
|
Javascript
<script>
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 ;
}
else if (visited[adj[v][i]] == true &&
recur[adj[v][i]] == true )
return true ;
}
recur[v] = false ;
return false ;
}
function isCycle(arr, n) {
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);
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 ;
}
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>
|
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 {
public static String checkLoop( int [] arr) {
int n = arr.length;
Set<Integer> visited = new HashSet<>();
int curr = 0 ;
while ( true ) {
if (visited.contains(curr)) {
return "yes" ;
}
if (arr[curr] == 0 || curr == (curr + arr[curr]) % n) {
return "no" ;
}
visited.add(curr);
curr = (curr + arr[curr]) % n;
}
}
public static void main(String[] args) {
int [] arr = { 2 , - 1 , 1 , 2 , 2 };
String result = checkLoop(arr);
System.out.println(result);
}
}
|
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
{
public static string CheckLoop( int [] arr)
{
int n = arr.Length;
HashSet< int > visited = new HashSet< int >();
int curr = 0;
while ( true )
{
if (visited.Contains(curr))
{
return "yes" ;
}
if (arr[curr] == 0 || curr == (curr + arr[curr]) % n)
{
return "no" ;
}
visited.Add(curr);
curr = (curr + arr[curr]) % n;
}
}
public static void Main( string [] args)
{
int [] arr = { 2, -1, 1, 2, 2 };
string result = CheckLoop(arr);
Console.WriteLine(result);
}
}
|
Javascript
function check_loop(arr) {
const n = arr.length;
const visited = new Set();
let curr = 0;
while ( true ) {
if (visited.has(curr)) {
return 'yes' ;
}
if (arr[curr] === 0 || curr === (curr + arr[curr]) % n) {
return 'no' ;
}
visited.add(curr);
curr = (curr + arr[curr]) % n;
}
}
const arr = [2, -1, 1, 2, 2];
console.log(check_loop(arr));
|
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
Share your thoughts in the comments
Please Login to comment...