数组中可以根据值跳转的循环元素的数量
给定一个包含 n 个整数的数组 arr[]。对于每个值 arr[i],我们可以顺时针移动到 arr[i] + 1
考虑循环中的数组元素。我们需要计算数组中的循环元素。如果从一个元素开始并移动到 arr[i] + 1 导致相同的元素,则该元素是循环的。
例子:
Input : arr[] = {1, 1, 1, 1}
Output : 4
All 4 elements are cyclic elements.
1 -> 3 -> 1
2 -> 4 -> 2
3 -> 1 -> 3
4 -> 2 -> 4
Input : arr[] = {3, 0, 0, 0}
Output : 1
There is one cyclic point 1,
1 -> 1
The path covered starting from 2 is
2 -> 3 -> 4 -> 1 -> 1.
The path covered starting from 3 is
2 -> 3 -> 4 -> 1 -> 1.
The path covered starting from 4 is
4 -> 1 -> 1
一种简单的解决方案是一一检查所有元素。我们遵循从每个元素 arr[i] 开始的简单路径,我们转到 arr[i] + 1。如果我们回到 arr[i] 以外的已访问元素,我们不计算 arr[i]。该解决方案的时间复杂度为 O(n 2 )
一个有效的解决方案基于以下步骤。
1)使用数组索引作为节点创建有向图。我们从 i 到节点 (arr[i] + 1)%n 添加一条边。
2) 创建图后,我们使用 Kosaraju 算法找到所有强连通分量
3)我们最终返回单个强连通分量中节点计数的总和。
C++
// C++ program to count cyclic points
// in an array using Kosaraju's Algorithm
#include
using namespace std;
// Most of the code is taken from below link
// https://www.geeksforgeeks.org/strongly-connected-components/
class Graph {
int V;
list* adj;
void fillOrder(int v, bool visited[],
stack& Stack);
int DFSUtil(int v, bool visited[]);
public:
Graph(int V);
void addEdge(int v, int w);
int countSCCNodes();
Graph getTranspose();
};
Graph::Graph(int V)
{
this->V = V;
adj = new list[V];
}
// Counts number of nodes reachable
// from v
int Graph::DFSUtil(int v, bool visited[])
{
visited[v] = true;
int ans = 1;
list::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
if (!visited[*i])
ans += DFSUtil(*i, visited);
return ans;
}
Graph Graph::getTranspose()
{
Graph g(V);
for (int v = 0; v < V; v++) {
list::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
g.adj[*i].push_back(v);
}
return g;
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w);
}
void Graph::fillOrder(int v, bool visited[],
stack& Stack)
{
visited[v] = true;
list::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
if (!visited[*i])
fillOrder(*i, visited, Stack);
Stack.push(v);
}
// This function mainly returns total count of
// nodes in individual SCCs using Kosaraju's
// algorithm.
int Graph::countSCCNodes()
{
int res = 0;
stack Stack;
bool* visited = new bool[V];
for (int i = 0; i < V; i++)
visited[i] = false;
for (int i = 0; i < V; i++)
if (visited[i] == false)
fillOrder(i, visited, Stack);
Graph gr = getTranspose();
for (int i = 0; i < V; i++)
visited[i] = false;
while (Stack.empty() == false) {
int v = Stack.top();
Stack.pop();
if (visited[v] == false) {
int ans = gr.DFSUtil(v, visited);
if (ans > 1)
res += ans;
}
}
return res;
}
// Returns count of cyclic elements in arr[]
int countCyclic(int arr[], int n)
{
int res = 0;
// Create a graph of array elements
Graph g(n + 1);
for (int i = 1; i <= n; i++) {
int x = arr[i-1];
// If i + arr[i-1] jumps beyond last
// element, we take mod considering
// cyclic array
int v = (x + i) % n + 1;
// If there is a self loop, we
// increment count of cyclic points.
if (i == v)
res++;
g.addEdge(i, v);
}
// Add nodes of strongly connected components
// of size more than 1.
res += g.countSCCNodes();
return res;
}
// Driver code
int main()
{
int arr[] = {1, 1, 1, 1};
int n = sizeof(arr)/sizeof(arr[0]);
cout << countCyclic(arr, n);
return 0;
}
Java
// Python3 program to count cyclic points
// in an array using Kosaraju's Algorithm
// Counts number of nodes reachable
// from v
import java.io.*;
import java.util.*;
class GFG
{
static boolean[] visited = new boolean[100];
static Stack stack = new Stack();
static ArrayList> adj =
new ArrayList>();
static int DFSUtil(int v)
{
visited[v] = true;
int ans = 1;
for(int i: adj.get(v))
{
if(!visited[i])
{
ans += DFSUtil(i);
}
}
return ans;
}
static void getTranspose()
{
for(int v = 0; v < 5; v++)
{
for(int i : adj.get(v))
{
adj.get(i).add(v);
}
}
}
static void addEdge(int v, int w)
{
adj.get(v).add(w);
}
static void fillOrder(int v)
{
visited[v] = true;
for(int i: adj.get(v))
{
if(!visited[i])
{
fillOrder(i);
}
}
stack.add(v);
}
// This function mainly returns total count of
// nodes in individual SCCs using Kosaraju's
// algorithm.
static int countSCCNodes()
{
int res = 0;
// stack Stack;
// bool* visited = new bool[V];
for(int i = 0; i < 5; i++)
{
if(visited[i] == false)
{
fillOrder(i);
}
}
getTranspose();
for(int i = 0; i < 5; i++)
{
visited[i] = false;
}
while(stack.size() > 0)
{
int v = stack.get(stack.size() - 1);
stack.remove(stack.size() - 1);
if (visited[v] == false)
{
int ans = DFSUtil(v);
if (ans > 1)
{
res += ans;
}
}
}
return res;
}
// Returns count of cyclic elements in arr[]
static int countCyclic(int[] arr, int n)
{
int res = 0;
// Create a graph of array elements
for(int i = 1; i < n + 1; i++)
{
int x = arr[i - 1];
// If i + arr[i-1] jumps beyond last
// element, we take mod considering
// cyclic array
int v = (x + i) % n + 1;
// If there is a self loop, we
// increment count of cyclic points.
if (i == v)
res++;
addEdge(i, v);
}
// Add nodes of strongly connected components
// of size more than 1.
res += countSCCNodes();
return res;
}
// Driver code
public static void main (String[] args)
{
int arr[] = {1, 1, 1, 1};
int n = arr.length;
for(int i = 0; i < 100; i++)
{
adj.add(new ArrayList());
}
System.out.println(countCyclic(arr, n));
}
}
// This code is contributed by avanitrachhadiya2155
Python3
# Python3 program to count cyclic points
# in an array using Kosaraju's Algorithm
# Counts number of nodes reachable
# from v
def DFSUtil(v):
global visited, adj
visited[v] = True
ans = 1
for i in adj[v]:
if (not visited[i]):
ans += DFSUtil(i)
return ans
def getTranspose():
global visited, adj
for v in range(5):
for i in adj[v]:
adj[i].append(v)
def addEdge(v, w):
global visited, adj
adj[v].append(w)
def fillOrder(v):
global Stack, adj, visited
visited[v] = True
for i in adj[v]:
if (not visited[i]):
fillOrder(i)
Stack.append(v)
# This function mainly returns total count of
# nodes in individual SCCs using Kosaraju's
# algorithm.
def countSCCNodes():
global adj, visited, S
res = 0
#stack Stack;
#bool* visited = new bool[V];
for i in range(5):
if (visited[i] == False):
fillOrder(i)
getTranspose()
for i in range(5):
visited[i] = False
while (len(Stack) > 0):
v = Stack[-1]
del Stack[-1]
if (visited[v] == False):
ans = DFSUtil(v)
if (ans > 1):
res += ans
return res
# Returns count of cyclic elements in arr[]
def countCyclic(arr, n):
global adj
res = 0
# Create a graph of array elements
for i in range(1, n + 1):
x = arr[i - 1]
# If i + arr[i-1] jumps beyond last
# element, we take mod considering
# cyclic array
v = (x + i) % n + 1
# If there is a self loop, we
# increment count of cyclic points.
if (i == v):
res += 1
addEdge(i, v)
# Add nodes of strongly connected components
# of size more than 1.
res += countSCCNodes()
return res
# Driver code
if __name__ == '__main__':
adj = [[] for i in range(100)]
visited = [False for i in range(100)]
arr = [ 1, 1, 1, 1 ]
Stack = []
n = len(arr)
print(countCyclic(arr, n))
# This code is contributed by mohit kumar 29
C#
// C# program to count cyclic points
// in an array using Kosaraju's Algorithm
// Counts number of nodes reachable
// from v
using System;
using System.Collections.Generic;
public class GFG
{
static bool[] visited = new bool[100];
static List stack = new List();
static List> adj = new List>();
static int DFSUtil(int v)
{
visited[v] = true;
int ans = 1;
foreach(int i in adj[v])
{
if(!visited[i])
{
ans += DFSUtil(i);
}
}
return ans;
}
static void getTranspose()
{
for(int v = 0; v < 5; v++)
{
foreach(int i in adj[v])
{
adj[i].Add(v);
}
}
}
static void addEdge(int v, int w)
{
adj[v].Add(w);
}
static void fillOrder(int v)
{
visited[v] = true;
foreach(int i in adj[v])
{
if(!visited[i])
{
fillOrder(i);
}
}
stack.Add(v);
}
// This function mainly returns total count of
// nodes in individual SCCs using Kosaraju's
// algorithm.
static int countSCCNodes()
{
int res = 0;
// stack Stack;
// bool* visited = new bool[V];
for(int i = 0; i < 5; i++)
{
if(visited[i] == false)
{
fillOrder(i);
}
}
getTranspose();
for(int i = 0; i < 5; i++)
{
visited[i] = false;
}
while(stack.Count > 0)
{
int v=stack[stack.Count - 1];
stack.Remove(stack.Count - 1);
if (visited[v] == false)
{
int ans = DFSUtil(v);
if (ans > 1)
{
res += ans;
}
}
}
return res;
}
// Returns count of cyclic elements in arr[]
static int countCyclic(int[] arr, int n)
{
int res = 0;
// Create a graph of array elements
for(int i = 1; i < n + 1; i++)
{
int x = arr[i - 1];
// If i + arr[i-1] jumps beyond last
// element, we take mod considering
//cyclic array
int v = (x + i) % n + 1;
// If there is a self loop, we
// increment count of cyclic points.
if (i == v)
res++;
addEdge(i, v);
}
// Add nodes of strongly connected components
// of size more than 1.
res += countSCCNodes();
return res;
}
// Driver code
static public void Main ()
{
int[] arr = {1, 1, 1, 1};
int n = arr.Length;
for(int i = 0; i < 100; i++)
{
adj.Add(new List());
}
Console.WriteLine(countCyclic(arr, n));
}
}
// This code is contributed by rag2127
Javascript
输出:
4
时间复杂度:O(n)
辅助空间:O(n) 注意只有 O(n) 条边。