Minimum p[i] = p[arr[i]] operations to regain the given Array
Last Updated :
01 Nov, 2022
Given an array, A[] (1 – indexed) of size ‘N’ which contains a permutation of [1, N], the task is to find the minimum number of operations to be applied on any array P[] to get back the original array P[]. The operation must be applied at least once. In each operation, for every index of P[] we set P[i] = P[A[i]].
Examples:
Input: A[] = {1, 3, 2}
Output: 2
Explanation: Let P[] = {7, 4, 2}.
After 1 operation, {P[1], P[3], P[2]} = {1, 2, 4}.
After 2 operations, {P[1], P[3], P[2]} = {7, 4, 2}
After 2 operation original array is reached.
Input: A[] = {5, 4, 2, 3, 1}
Output: 6
Explanation: Let P = {1, 2, 3, 4, 5},
After 1 operation {P[5], P[4], P[2], P[3], P[1]} = {5, 4, 2, 3, 1}
After 2 operation {P[5], P[4], P[2], P[3], P[1]} = {1, 3, 4, 2, 5}
After 3 operation {P[5], P[4], P[2], P[3], P[1]} = {5, 2, 3, 4, 1}
After 4 operation {P[5], P[4], P[2], P[3], P[1]} = {1, 4, 2, 3, 5}
After 5 operation {P[5], P[4], P[2], P[3], P[1]} = {5, 3, 4, 2, 1}
After 6 operation {P[5], P[4], P[2], P[3], P[1]} = {1, 2, 3, 4, 5}
After 6 operation original array is reached.
Naive Approach:
A naive approach is to make any array and apply the given operation until the original array is reached again.
Below is the implementation of the approach.
C++
#include <bits/stdc++.h>
using namespace std;
bool checkEqual(vector< int >& A, vector< int >& B)
{
for ( int i = 0; i < A.size(); i++) {
if (A[i] != B[i])
return false ;
}
return true ;
}
int minOperations(vector< int >& A)
{
int N = A.size();
vector< int > P(N, 0);
vector< int > originalArray(N, 0);
for ( int i = 0; i < N; i++) {
P[i] = A[i];
originalArray[i] = P[i];
}
for ( int i = 0; i < N; i++) {
P[i] = A[A[i] - 1];
}
int operations = 1;
while (!checkEqual(originalArray, P)) {
vector< int > temp(N);
for ( int i = 0; i < N; i++) {
temp[i] = P[A[i] - 1];
}
P = temp;
operations++;
}
return operations;
}
int main()
{
vector< int > A = { 5, 4, 2, 3, 1 };
cout << minOperations(A);
return 0;
}
|
Java
import java.util.*;
public class GFG {
static boolean checkEqual( int [] A, int [] B)
{
for ( int i = 0 ; i < A.length; i++) {
if (A[i] != B[i])
return false ;
}
return true ;
}
static int minOperations( int [] A)
{
int N = A.length;
int [] P = new int [N];
int [] originalArray = new int [N];
for ( int i = 0 ; i < N; i++) {
P[i] = A[i];
originalArray[i] = P[i];
}
for ( int i = 0 ; i < N; i++) {
P[i] = A[A[i] - 1 ];
}
int operations = 1 ;
while (!checkEqual(originalArray, P)) {
int [] temp = new int [N];
for ( int i = 0 ; i < N; i++) {
temp[i] = P[A[i] - 1 ];
}
P = temp;
operations++;
}
return operations;
}
public static void main(String[] args)
{
int [] A = { 5 , 4 , 2 , 3 , 1 };
System.out.println(minOperations(A));
}
}
|
Python3
def checkEqual(A, B):
for i in range ( len (A)):
if (A[i] is not B[i]):
return False
return True
def minOperations(A):
N = len (A)
P = [ 0 ] * N
originalArray = [ 0 ] * N
for i in range (N):
P[i] = A[i]
originalArray[i] = P[i]
for i in range (N):
P[i] = A[A[i] - 1 ]
operations = 1
while (checkEqual(originalArray, P) is not True ):
temp = [ 0 ] * N
for i in range (N):
temp[i] = P[A[i] - 1 ]
P = temp
operations + = 1
return operations
A = [ 5 , 4 , 2 , 3 , 1 ]
print (minOperations(A))
|
C#
using System;
using System.Collections.Generic;
class GFG
{
static bool checkEqual( int [] A, int [] B)
{
for ( int i = 0; i < A.Length; i++) {
if (A[i] != B[i])
return false ;
}
return true ;
}
static int minOperations( int [] A)
{
int N = A.Length;
int [] P = new int [N];
int [] originalArray = new int [N];
for ( int i = 0; i < N; i++) {
P[i] = A[i];
originalArray[i] = P[i];
}
for ( int i = 0; i < N; i++) {
P[i] = A[A[i] - 1];
}
int operations = 1;
while (!checkEqual(originalArray, P)) {
int [] temp = new int [N];
for ( int i = 0; i < N; i++) {
temp[i] = P[A[i] - 1];
}
P = temp;
operations++;
}
return operations;
}
public static void Main(String[] args)
{
int [] A = { 5, 4, 2, 3, 1 };
Console.WriteLine(minOperations(A));
}
}
|
Javascript
<script>
function checkEqual(A, B)
{
for (let i = 0; i < A.length; i++) {
if (A[i] != B[i])
return false ;
}
return true ;
}
function minOperations(A)
{
let N = A.length;
let P = new Array(N);
let originalArray = new Array(N);
for (let i = 0; i < N; i++) {
P[i] = A[i];
originalArray[i] = P[i];
}
for (let i = 0; i < N; i++) {
P[i] = A[A[i] - 1];
}
let operations = 1;
while (!checkEqual(originalArray, P)) {
let temp = new Array(N);
for (let i = 0; i < N; i++) {
temp[i] = P[A[i] - 1];
}
P = temp;
operations++;
}
return operations;
}
let A = [ 5, 4, 2, 3, 1 ];
document.write(minOperations(A));
</script>
|
Time Complexity: O(N * minOperations), for executing the operations until the original array is retrieved.
Auxiliary Space: O(N), for creating an additional array of size P.
Efficient Approach:
Use the following idea to solve the problem:
It can be observed that the elements form a cycle. When all the cycles are completed at the same operation for the first time that many moves are required.
Each cycle is completed after making moves same as their length. So all the cycles are completed at the same operation for the first time when LCM(all cycle lengths) number of moves are made.
Follow the below steps to solve the problem:
- Declare an array ‘cycleLengths[]’ to store the length of all cycles present.
- Declare a Boolean array ‘visited[]’ to check if the cycle length of corresponding element has already been calculated or not.
- For every unvisited index
- traverse all the elements of corresponding cycle while updating the ‘visited[]’ and store its length in ‘cycleLength[]’.
- Return the LCM of all numbers present in ‘cycleLength[]’.
Code implementation of above approach:
C++
#include <iostream>
#include <vector>
using namespace std;
int gcd( int a, int b)
{
if (a == 0)
return b;
return gcd(b % a, a);
}
int lcm( int a, int b) { return (a * b) / gcd(a, b); }
int traverseCycle( int root, int A[], vector< int >& visited)
{
if (visited[root])
return 0;
visited[root] = true ;
return 1 + traverseCycle(A[root - 1], A, visited);
}
int minOperations( int A[], int N)
{
vector< int > cycleLength;
vector< int > visited(N + 1, 0);
for ( int i = 1; i <= N; i++) {
if (!visited[i]) {
int len = traverseCycle(i, A, visited);
cycleLength.push_back(len);
}
}
int res = 1;
for ( auto cycleLen : cycleLength) {
res = lcm(res, cycleLen);
}
return res;
}
int main()
{
int A[] = { 5, 4, 2, 3, 1 };
cout << (minOperations(A, 5)) << endl;
;
}
|
Java
import java.util.*;
public class GFG {
static int gcd( int a, int b)
{
if (a == 0 )
return b;
return gcd(b % a, a);
}
static int lcm( int a, int b)
{
return (a * b) / gcd(a, b);
}
static int traverseCycle( int root, int [] A,
boolean [] visited)
{
if (visited[root])
return 0 ;
visited[root] = true ;
return 1 + traverseCycle(A[root - 1 ], A, visited);
}
static int minOperations( int [] A)
{
int N = A.length;
ArrayList<Integer> cycleLength = new ArrayList<>();
boolean [] visited = new boolean [N + 1 ];
for ( int i = 1 ; i <= N; i++) {
if (!visited[i]) {
int len = traverseCycle(i, A, visited);
cycleLength.add(len);
}
}
int res = 1 ;
for (Integer cycleLen : cycleLength) {
res = lcm(res, cycleLen);
}
return res;
}
public static void main(String[] args)
{
int [] A = { 5 , 4 , 2 , 3 , 1 };
System.out.println(minOperations(A));
}
}
|
Python3
class GFG:
@staticmethod
def gcd(a, b):
if (a = = 0 ):
return b
return GFG.gcd(b % a, a)
@staticmethod
def lcm(a, b):
return int ((a * b) / GFG.gcd(a, b))
@staticmethod
def traverseCycle(root, A, visited):
if (visited[root]):
return 0
visited[root] = True
return 1 + GFG.traverseCycle(A[root - 1 ], A, visited)
@staticmethod
def minOperations(A):
N = 5
cycleLength = []
visited = [ False ] * (N + 1 )
i = 1
while (i < = N):
if ( not visited[i]):
len = GFG.traverseCycle(i, A, visited)
cycleLength.append( len )
i + = 1
res = 1
for cycleLen in cycleLength:
res = GFG.lcm(res, cycleLen)
return res
@staticmethod
def main(args):
A = [ 5 , 4 , 2 , 3 , 1 ]
print (GFG.minOperations(A))
if __name__ = = "__main__" :
GFG.main([])
|
C#
using System;
using System.Collections.Generic;
public class GFG
{
static int gcd( int a, int b)
{
if (a == 0)
return b;
return gcd(b % a, a);
}
static int lcm( int a, int b)
{
return (a * b) / gcd(a, b);
}
static int traverseCycle( int root, int [] A,
Boolean[] visited)
{
if (visited[root])
return 0;
visited[root] = true ;
return 1 + traverseCycle(A[root - 1], A, visited);
}
static int minOperations( int [] A)
{
int N = A.Length;
List< int > cycleLength = new List< int >();
Boolean[] visited = new Boolean[N + 1];
for ( int i = 1; i <= N; i++)
{
if (!visited[i])
{
int len = traverseCycle(i, A, visited);
cycleLength.Add(len);
}
}
int res = 1;
foreach ( int cycleLen in cycleLength)
{
res = lcm(res, cycleLen);
}
return res;
}
public static void Main()
{
int [] A = { 5, 4, 2, 3, 1 };
Console.Write(minOperations(A));
}
}
|
Javascript
function gcd(a, b)
{
if (a == 0)
return b;
return gcd(b % a, a);
}
function lcm(a, b)
{
let c = a * b;
return (c / gcd(a, b));
}
function traverseCycle(root, A, visited)
{
if (visited[root])
return 0;
visited[root] = true ;
return 1 + traverseCycle(A[root - 1], A, visited);
}
function minOperations(A, N)
{
let cycleLength = [];
let visited = [];
for (let i = 0; i <= N; i++) {
visited.push(0);
}
for (let i = 1; i <= N; i++) {
if (visited[i] == false ) {
let len = traverseCycle(i, A, visited);
cycleLength.push(len);
}
}
let res = 1;
for (let i = 0; i < cycleLength.length; i++) {
res = lcm(res, cycleLength[i]);
}
return res;
}
let A = [ 5, 4, 2, 3, 1 ];
console.log(minOperations(A, 5));
|
Time Complexity: O(N*log(Arr[i])), where N is the size of the given array.
Auxiliary Space: O(N), for creating an additional array of size N + 1.
Share your thoughts in the comments
Please Login to comment...