This question was asked in one interview and i am still hunting for the best solution.
You are given a maze with N cells. Each cell may have multiple entry points but not more than one exit
(ie. entry/exit points are unidirectional doors like valves).
The cells are named with an integer value from 0
to N-1.
You need to find the the length of the largest cycle in the maze. Return -1 if there are no cycles.
INPUT FORMAT
First line has the number of cells N
Second line has list of N values of the edge[] array. edge[i] contains the cell number that
can be reached from of cell ‘i’ in one step. edge[i] is -1 if the ‘i’th cell doesn’t have an exit.
OUTPUT FORMAT
length of the largest cycle.
Sample input:
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
Sample output
6
I have already tried to do this with DFS to find all possible cycles and print the largest cycle size.
Please let me know if there is any better solution for the same.
Given a node in the graph, there's a unique maximal path starting from it (since there's at most one exit from any node). It may or may not cycle.
It's easy to find the eventual cycle length starting from a node: keep following exit nodes, recording nodes in a set along the path. Stop when you either find no exit node, or you're about to visit a previously visited node. If there's no exit node there's no cycle, and otherwise you can find the cycle length by starting at the previously visited node, and re-trace the cycle. [You could also use Floyd's algorithm here which would require O(1) rather than O(N) storage, but we're going to use O(N) storage anyway in the next step].
Using this, one can find the maximum cycle in O(N) time: repeat the above algorithm for each node in the graph, but cache results (storing -1 if there's no cycle found). You have to be careful to stop the cycle-finding above if you find a previously cached result along your path, and once you've found a result for a node, you must cache the result for all nodes along the path until you find a node who's result is already cached. The size of the largest cycle is the value of the largest cached value.
This is O(N) runtime: each edge (of which there's at most N) is followed at most 3 times in the graph, and the cache is updated exactly once for each node in the graph. It's uses O(N) additional storage.
public static int solution(int arr[])
{
ArrayList<Integer> sum = new ArrayList<>();
for(int i = 0; i < arr.length; i ++)
{
ArrayList<Integer> path = new ArrayList<>();
int j = i;
int tempSum = 0;
while(arr[j]<arr.length && arr[j]!=i && arr[j]!=-1 && !path.contains(j))
{
path.add(j);
tempSum+=j;
j=arr[j];
if(arr[j]==i)
{
tempSum+=j;
break;
}
}
if(j<arr.length && i == arr[j])
sum.add(tempSum);
}
if(sum.isEmpty())
return -1;
return Collections.max(sum);
}
Here is an implementation in JavaScript. I didn't use any fancy features of JavaScript, so the algorithm can be readily seen from the code. On the other hand, it does need ES6 support to run (forget IE):
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>
This runs in O(n). Even though the outer loop has both a nested loop and an expression that iterates over an array (using slice and indexOf), these sub-iterations are only executed once per cell, so in total this is still O(n).
The function does not only return the cycle size, but also the array containing the list of cells that belong to that cycle. It is a small overhead, but allows to better verify the result.
Python implementation of the solution suggested by trincot.
Explanation:
iterate over each node
For each node use the indices to navigate to the next node. Eg(1st iteration : outer for loop)
from 0th index we can reach 4 , from 4th index we can reach 13 , and from 13th index we can reach 11, and so on till we reach the visited node again in our case 0,
viola , we have found the first cycle.
check if visitedFrom[cell] == startCell i.e. 0 add it to the result array.
repeat for next node (step1)
Code
def largestCycle(edges):
result = []
visitedFrom = [-1] * len(edges)
for startCell in range(0, len(edges)):
cells = []
cell = startCell
while cell > -1 and visitedFrom[cell] == -1:
visitedFrom[cell] = startCell
cells.append(cell)
cell = edges[cell]
if cell > -1 and visitedFrom[cell] == startCell:
cells_idx = cells.index(cell)
cells = cells[cells_idx:]
if len(cells) > len(result):
result = cells
return result,len(result)
size = 23
edges = [4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21]
largestCycle(edges)
Using Prims algorithm to Find max Cycle in the Node
n = int(input())
v = n
e = v+1
arr = [int(i) for i in input().split()]
graph = [[0 for _ in range(n)] for _ in range(n)]
for i in range(0, len(arr)):
graph[i][arr[i]] = 1
for i in graph:
print(i)
def min_ind(wieight, visied):
min_ = -1
ind = -1
for i in range(v):
if(wieight[i] > min_ and visied[i] == False):
min_ = wieight[i]
ind = i
return ind
def printPath(parent, i):
res = []
while(parent[i] != -1):
res.append(i)
i = parent[i]
res.append(i)
return res[::-1]
# Dijkstra
visited = [False for _ in range(v)]
wieight = [0 for _ in range(v)]
parent = [-1 for i in range(v)]
wieight[0] = 0
path = []
for _ in range(v):
u = min_ind(wieight, visited)
if(u == -1):
continue
visited[u] = True
for i in range(v):
if(graph[u][i] > 0 and visited[i] == False):
if(wieight[i] < graph[u][i]):
wieight[i] = graph[u][i]
parent[i] = u
maximum = 0
for i in range(0, len(wieight)):
print("No:", i, " Weight:", wieight[i], " Path:", end=" ")
path = (printPath(parent, i))
maximum = max(maximum, len(path))
print(path, end=" ")
print()
print("Longest Cycle: ", maximum)
here is the solution for the problem but input format is not actually the same.
Here is the input format:
test cases: N
size of array: M
array elements: 1<=a(i)<=M-1 where 0<=i<=M-1
index to which last index points: C
In this problem, we have to count the cells in the largest cycle, here is the code:
class countLargestCycleMaze {
static vertex[] cells;
static class vertex {
int name;
neighbor list;
public vertex(int v, neighbor nb) {
this.name = v;
this.list = nb;
}
}
static class neighbor {
int vnum;
neighbor next;
public neighbor(int v, neighbor nb) {
this.vnum = v;
this.next = nb;
}
}
static int dfs(int v, int m) {
neighbor tmp = cells[v].list;
int c = 0;
while (tmp.vnum != m)
tmp = cells[tmp.vnum].list;
tmp = cells[tmp.vnum].list;
while (tmp.vnum != m) {
tmp = cells[tmp.vnum].list;
c++;
}
return c;
}
public static void main(String[] args) throws java.lang.Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int i, j, n, m, c;
n = Integer.parseInt(br.readLine());
while (n-- > 0) {
m = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
c = Integer.parseInt(br.readLine());
if (c == 0) {
System.out.println("0");
continue;
}
cells = new vertex[m + 1];
for (i = 0; i < m; i++) {
int num = Integer.parseInt(st.nextToken());
cells[i] = new vertex(num, null);
cells[i].list = new neighbor(num, cells[i].list);
}
cells[m] = new vertex(c, null);
cells[m].list = new neighbor(c, cells[m].list);
System.out.println(dfs(0, c));
}
} catch (Exception e) {}
}
}
public class LargestCycleInGraph {
public static int checkCycle(int []cell , int size , int start) {
Set<Integer> set = new HashSet<>();
set.add(start);
for(int i = start ;i< size;i++) {
if( !set.contains(cell[i]) && cell[i] != -1) {
set.add( cell[i] );
}
else return set.size() + 1; // 1 for again come to cycle node
}
return -1;
}
public static int findLargestCycle(int []cell , int size) {
int max = -1;
for(int i =0;i<size;i++) {
//if you want to find sum of largest cycle return "Set" rather than its size and check for max sum
int cyc = checkCycle(cell , size , i);
if(max < cyc)
max = cyc;
}
return max;
}
public static void main(String[] args) {
int size = 23;
int []cell = {4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21};
int largestCycle = findLargestCycle(cell , size);
System.out.println("Largest cycle Length " +largestCycle);
}
}
def main():
size = int(input())
cell = input().split()
for i in range(0, len(cell)):
cell[i] = int(cell[i])
m = -1
for i in range(0, 23):
if m < check_cycle(cell, i):
m = check_cycle(cell, i)
print("Largest cycle is made of", m, "nodes")
def check_cycle(cell, start):
i = start
if i in cell:
cycle = [i]
j = i
while 1:
for k in cycle:
if cycle.count(k) >= 2:
if cycle[0] == cycle[-1]:
return len(cycle)-1
else:
return 0
else:
cycle.append(cell[j])
j = cell[j]
else:
return 0
main()
Here is my attempt, to traverse each node of the graph:-
#include <stdio.h>
int findingLargestCycle(int noOfInputs, int *edges){
int largestCycle = 0;
for(int i=0; i<noOfInputs; i++){
int currentEdge = edges[i];
int count = currentEdge;
int nextEdge = edges[currentEdge];
int n = 0;
while(currentEdge != nextEdge && n<noOfInputs+1){
if(nextEdge == -1 || currentEdge == -1){
count = 0;
break;
}
if(nextEdge != currentEdge){
count += nextEdge;
}
nextEdge = edges[nextEdge];
n++;
}
if(count > largestCycle && n != noOfInputs+1){
largestCycle = count;
}
}
return largestCycle;
}
int main(){
int testCases;
scanf("%d", &testCases);
int numberOfInputs;
scanf("%d", &numberOfInputs);
int edges[numberOfInputs];
for(int i=0; i<numberOfInputs; i++){
scanf("%d", &edges[i]);
}
printf("%d", findingLargestCycle(numberOfInputs, &edges[0]));
}
O(n) time complexity solution each node is visited only after checking it's visited before or not, so each node is visited only once.
O(n) space complexity ([n]:stack space max + [2*n]:two map used max size)
To observe: there is always a unique path between two nodes(check with any test case), because of condition, only one exit from each node.
C++ code:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
//res stores result
int res = 0;
//visit to check in before visiting the node, to stop repeat visiting
unordered_map<int,bool> visit;
void dfs(vector<int> & a, unordered_map<int,int> &mp, int i, int k){
if(visit.find(i) != visit.end())
return;
if(a[i] == -1){
visit[i] = true;
return;
}
if(mp.find(i) != mp.end()){
res = max(res, k-mp[i]);
visit[i] = true;
return;
}
mp[i] = k;
dfs(a, mp, a[i], k+1);
visit[i] = true;
}
int main() {
int n;
cin>>n;
vector<int> a(n,0);
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++){
if(visit.find(i) == visit.end()){
unordered_map<int,int> mp;
dfs(a, mp, i, 0);
}
}
cout<<res<<endl;
return 0;
}
Solution in C++
#include <bits/stdc++.h>
using namespace std;
bool isCycle(vector<int> arr, int curr, vector<bool> &visited, vector<int> &path)
{
if (curr == -1)
{
return false;
}
if (visited[curr])
{
return true;
}
visited[curr] = true;
path.emplace_back(curr);
if (isCycle(arr, arr[curr], visited, path))
return true;
return false;
}
int largestSumCycle(vector<int> arr)
{
int n = arr.size();
int sum = INT_MIN;
vector<bool> visited(n, false);
for (int i = 0; i < n; i++)
{
visited[i] = true;
vector<int> path;
if (isCycle(arr, arr[i], visited, path))
sum = max(sum, accumulate(path.begin(), path.end(), 0));
visited[i] = false;
}
if (sum == INT_MIN)
return -1;
return sum;
}
This is a common question in interviews, in the same interview they asked this question also for the same details in question.
Q: find the NEAREST MEETING CELL (NMC)
INPUT : same as above + third line has 2 numbers whose nearest meeting cell is to be found.
SAMPLE INPUT
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
9 2 (need to find out meeting point of 9 , 2 in the mesh/graph)
OUTPUT
4
CODE:
def main():
testCASES=int(input())
# testCASES=1
for case_number in range(testCASES):
meshsize=input()
mesh=input()
# mesh='4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21'
det=input()
# det='9 2'
mesh=[int(x) for x in mesh.split()]
det=[int(x) for x in det.split()]
n1=det[0]
n2=det[1]
n1path=[]
n2path=[]
for i in range(len(mesh)):
if not n1path:
n1path.append(mesh[n1])
else:
n1path.append(mesh[n1path[i-1]])
if not n2path:
n2path.append(mesh[n2])
else:
n2path.append(mesh[n2path[i-1]])
nearestList=[]
try:
for x in n1path:
nearestList.append(n2path.index(x))
NEAREST_NODE=n2path[min(nearestList)]
except Exception as e:
NEAREST_NODE = -1
# print(n1path,n2path)
print(NEAREST_NODE)
main()
WORKING:
walks paths from given 2 points, and calculate first common point of n1path and n2path, by using min() function on indices of nearest list. naming is arbitary, but thats the core algo.
it can handle if cycles are present, and still return the first intersection point.
returns -1 if no matches are found.
This is one more variant of the problem, apart from the normal inpt, we're given two nodes, src and dest, and we have to output the node which is the closest to both src and dest.
Here's my solution to finding nearest cell from both src and dest
#include<bits/stdc++.h>
using namespace std;
//returns answer
int solution(vector<int> arr, int src, int dest){
// Two maps, visA for distance from src and visB for distance from dest
// They serve two purpose, if visA[x] == 0, that means we haven't reached that node yet,
// and if it holds any value, say d, that means it is d distance away from the particular node
map<int,int> visA,visB;
int start = arr[src];
int curr = 1;
set<int> s; // contains unique set of nodes to check at last
// iniitializing final nodes
for(auto &x: arr){
s.insert(x);
}
// traversing until we get to a cell where we've already reached
while(visA[start] == 0){
visA[start] = curr; // Marcking the distance
curr++;
start = arr[start];
if(start == -1){
break; // Getting out if we get to a node who is not pointing at any other node
}
}
start = arr[dest];
// Same logic as above but traversing from dest
while(visB[start] == 0){
visB[start] = curr;
curr++;
start = arr[start];
if(start == -1){
break;
}
}
// This is an array of two values, vp[i].first holds the sum of distance of vp[i].second from src and dest.
vector<pair<int,int>> vp;
for(auto &x: s){
if(visA[x] != 0 && visB[x] != 0){ // Checking if we ever got to that particular node from both src and dest or not
pair<int,int> p = {visA[x] + visB[x], x};
vp.push_back(p);
}
}
// sorting and finding the node with list sum of visA[} + visB[]
sort(vp.begin(), vp.end());
return vp[0].second;
}
int main(){
int n; cin>>n;
vector<int> v;
for(int i = 0; i<n; i++){
int a; cin>>a;
v.push_back(a);
}
int a,b; cin>>a>>b;
cout << (solution(v,a,b));
}
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>
I recently encountered this problem in an interview
There are n stairs, a person standing at the bottom wants to reach the top. The person can climb either 1 stair or 2 stairs at a time.
Print all possible ways person can reach the top.
For example, n=4 Output:
1 2 3 4
1 2 4
1 3 4
2 3 4
2 4
But I couldn't code this properly. How to code up solution for this?
To print the number of ways, you can first understand how to calculate the number of ways, and adjust it so each "count" will print instead of just count:
D(0) = 1
D(-1) = 0
D(i) = D(i-1) + D(i-2)
To adjust it to actual printing, you need to "remember" the choices you have made, and follow the same logic. Pseudo code:
printWays(curr, n, soFar):
if curr > n:
return
soFar.append(curr)
if n == curr:
print soFar
soFar.removeLast()
return
printWays(curr+1,n,soFar)
printWays(curr+2,n,soFar)
soFar.removeLast()
The idea is:
soFar is the current series of steps you did.
curr is the current step you're at.
n is the last stair you need to get to.
At each point, you either climb one stair or two. You check both options.
You can try some recursive solution where you call recursively CanClimb(n-1) and CanClimb(n-2) to visualize the possible ways.
Sample solution in C#:
public static void ClimbWays(int n, int currentIndex, int[] currectClimb)
{
if (n < 0) return;
if (n == 0)
{
for (var i = currentIndex - 1; i >= 0; i--)
{
Console.Write(currectClimb[i] + " ");
}
Console.WriteLine();
return;
}
currectClimb[currentIndex] = n;
ClimbWays(n - 1, currentIndex + 1, currectClimb);
ClimbWays(n - 2, currentIndex + 1, currectClimb);
}
Output for ClimbWays(4, 0, new int[4]);:
1 2 3 4
2 3 4
1 3 4
1 2 4
2 4
If you want to just count them you can use the well known Fibonacci sequence which can be calculated iteratively:
public static int Fibonacci(int n)
{
int a = 0;
int b = 1;
// In N steps compute Fibonacci sequence iteratively.
for (int i = 0; i < n; i++)
{
int temp = a;
a = b;
b = temp + b;
}
return a;
}
The reason I'm asking this question is because I cannot see why the way I think cannot be applied to this particular question
"How would you design a stack which,
in addition to push and pop, also has a function min which returns the minimum element? Push, pop and min should all operate in O(1) time"
My basic solution: Wouldn't it be possible if we had a variable in stack class, that whenever we were pushing an item to stack we would check if it is smaller than our min variable. If it is assign the value to the min, if not ignore.
You would still get the O(1) as the min function would be;
int getMinimum(){
return min;
}
Why this solution is never mentioned, or what is the fault with the way I think?
This wouldn't work if you popped numbers off the stack.
Ex. 2,4,5,3,1. After you pop 1 off, what is your minimum?
The solution is to keep a stack of minimums, not just a single value. If you encounter a value that is less than equal to the current minimum, you need to push it onto the min-stack.
Ex.
Push(4):
Stack: 4
Min-stack: 4
Push(2):
Stack: 4 2
Min-stack: 4 2
Push(2):
Stack: 4 2 2
Min-stack: 4 2 2
Push(5):
Stack: 4 2 2 5
Min-stack: 4 2 2
Push(3):
Stack: 4 2 2 5 3
Min-stack: 4 2 2
Push(1):
Stack: 4 2 2 5 3 1
Min-stack: 4 2 2 1
Pop():
Stack: 4 2 2 5 3
Min-stack: 4 2 2
Pop():
Stack: 4 2 2 5
Min-stack: 4 2 2
Pop():
Stack: 4 2 2
Min-stack: 4 2 2
Pop():
Stack: 4 2
Min-stack: 4 2
Pop():
Stack: 4
Min-stack: 4
Use a linked list to keep track of the minimum value which is gonna be the head.
Note that linkedlist.app= append ( we put the value in the tail ).
linkedlist.pre =prepend ( we put the value as the head of the linkedlist)
public class Stack {
int[] elements;
int top;
Linkedlists min;
public Stack(int n) {
elements = new int[n];
top = 0;
min = new Linkedlists();
}
public void realloc(int n) {
int[] tab = new int[n];
for (int i = 0; i < top; i++) {
tab[i] = elements[i];
}
elements = tab;
}
public void push(int x) {
if (top == elements.length) {
realloc(elements.length * 2);
}
if (top == 0) {
min.pre(x);
} else if (x < min.head.data) {
min.pre(x);
} else {
min.app(x);
}
elements[top++] = x;
}
public int pop() {
int x = elements[--top];
if (top == 0) {
}
if (this.getMin() == x) {
min.head = min.head.next;
}
elements[top] = 0;
if (4 * top < elements.length) {
realloc((elements.length + 1) / 2);
}
return x;
}
public void display() {
for (Object x : elements) {
System.out.print(x + " ");
}
}
public int getMin() {
if (top == 0) {
return 0;
}
return this.min.head.data;
}
public static void main(String[] args) {
Stack stack = new Stack(4);
stack.push(2);
stack.push(3);
stack.push(1);
stack.push(4);
stack.push(5);
stack.pop();
stack.pop();
stack.pop();
stack.push(1);
stack.pop();
stack.pop();
stack.pop();
stack.push(2);
System.out.println(stack.getMin());
stack.display();
}
}
I found this solution here
struct StackGetMin {
void push(int x) {
elements.push(x);
if (minStack.empty() || x <= minStack.top())
minStack.push(x);
}
bool pop() {
if (elements.empty()) return false;
if (elements.top() == minStack.top())
minStack.pop();
elements.pop();
return true;
}
bool getMin(int &min) {
if (minStack.empty()) {
return false;
} else {
min = minStack.top();
return true;
}
}
stack<int> elements;
stack<int> minStack;
};