patternjavaMinor
Moving chips between cells
Viewed 0 times
cellsbetweenmovingchips
Problem
Challenge:
You are given a line of N cells with positive integers written in them. Initially a chip is placed on the leftmost cell. Each time it can be moved in any direction (to the left or to the right) on a neighboring cell or across the neighboring cell on the next one. The move is valid if the two numbers - the one the chip is standing on and the one the chip is going to be moved onto - have a common divisor greater than one. How far to the right is it possible to move a chip?
I have a working (I think) method of passing this challenge by recursively checking this method until it finds the optimum solution. I know this is probably the slowest way to do this (\$O(n!)\$?), and it seems that this isn't good enough, because the website I'm submitting my answer to says that I've exceeded my time limit.
Is there any way I can speed up this code?
You are given a line of N cells with positive integers written in them. Initially a chip is placed on the leftmost cell. Each time it can be moved in any direction (to the left or to the right) on a neighboring cell or across the neighboring cell on the next one. The move is valid if the two numbers - the one the chip is standing on and the one the chip is going to be moved onto - have a common divisor greater than one. How far to the right is it possible to move a chip?
I have a working (I think) method of passing this challenge by recursively checking this method until it finds the optimum solution. I know this is probably the slowest way to do this (\$O(n!)\$?), and it seems that this isn't good enough, because the website I'm submitting my answer to says that I've exceeded my time limit.
Is there any way I can speed up this code?
int chipMoving(int[] a) {
if(a.length == 1)return 0; //base case
int b = a[0], c = a[1],d = b;
while (c!=0){
int f = c;
c = b%c;
b = f;
}//b is now gcd of a[0] and a[1]
if(a.length == 2)return b1 && d1 && b rightMax)return 1+leftMax;
return 2+rightMax;
}Solution
I am not convinced that your code works correctly. For example if I run it with the
My other concern is that you only move the chip forward, although it might be necesarry to move it backwards. For example:
You can get to the 3 on index 5, but only if you step back from the 15 to the 3. Here is the route:
Your approach is to simulate the optimal route of the chip and the return the result. A cleaner approach would be to calculate all visitable positions and then return the rightmost.
This problem can be naturally interpreted as a graph traversal. The nodes are the cells, and an edge is defined between two nodes if the difference of their indices are at most 2, and they have a common divisor greater then 1.
For this you need a function that finds the greates common divisor. For example:
One that tells you if an edge exists between two nodes:
You need to mark all visited cell using a breath first traversal:
And then find the rightmost visited cell:
The runtime characteristics of finding the visited cells is \$O(N)\$, searching for the rightmost visited is also \$O(N)\$. That makes together \$O(N)\$.
{5,3,15,1,1,3,1} input it will result in 6 what is definietly wrong. (Nothing can have a common divisor with 1 greater than 1).My other concern is that you only move the chip forward, although it might be necesarry to move it backwards. For example:
{5, 3, 15, 9, 1, 3, 1}You can get to the 3 on index 5, but only if you step back from the 15 to the 3. Here is the route:
0 -> 2 -> 1 -> 3 -> 5Your approach is to simulate the optimal route of the chip and the return the result. A cleaner approach would be to calculate all visitable positions and then return the rightmost.
This problem can be naturally interpreted as a graph traversal. The nodes are the cells, and an edge is defined between two nodes if the difference of their indices are at most 2, and they have a common divisor greater then 1.
For this you need a function that finds the greates common divisor. For example:
int gcd(long a, long b) {
if (b==0)
return a;
else
return gcd(b, a % b);
}One that tells you if an edge exists between two nodes:
boolean edge(int[] a, int i, int j){
return gcd(a[i], a[j]) > 1;
}You need to mark all visited cell using a breath first traversal:
private static boolean[] getVisited(int[] a) {
boolean[] visited = new boolean[a.length];
Queue toVisit = new LinkedList();
toVisit.add(0);
while (!toVisit.isEmpty()) {
int i = toVisit.remove();
if (visited[i])
continue;
visited[i] = true;
if (i - 2 >= 0 && !visited[i - 2] && edge(a, i, i - 2))
toVisit.add(i - 2);
if (i - 1 >= 0 && !visited[i - 1] && edge(a, i, i - 1))
toVisit.add(i - 1);
if (i + 2 < a.length && !visited[i + 2] && edge(a, i, i + 2))
toVisit.add(i + 2);
if (i + 1 < a.length && !visited[i + 1] && edge(a, i, i + 1))
toVisit.add(i + 1);
}
return visited;
}And then find the rightmost visited cell:
int chipMoving(int[] a) {
boolean[] visited = getVisited(a);
for (int i = visited.length - 1; i >= 0; --i)
if (visited[i])
return i;
return 0;
}The runtime characteristics of finding the visited cells is \$O(N)\$, searching for the rightmost visited is also \$O(N)\$. That makes together \$O(N)\$.
Code Snippets
{5, 3, 15, 9, 1, 3, 1}0 -> 2 -> 1 -> 3 -> 5int gcd(long a, long b) {
if (b==0)
return a;
else
return gcd(b, a % b);
}boolean edge(int[] a, int i, int j){
return gcd(a[i], a[j]) > 1;
}private static boolean[] getVisited(int[] a) {
boolean[] visited = new boolean[a.length];
Queue<Integer> toVisit = new LinkedList<Integer>();
toVisit.add(0);
while (!toVisit.isEmpty()) {
int i = toVisit.remove();
if (visited[i])
continue;
visited[i] = true;
if (i - 2 >= 0 && !visited[i - 2] && edge(a, i, i - 2))
toVisit.add(i - 2);
if (i - 1 >= 0 && !visited[i - 1] && edge(a, i, i - 1))
toVisit.add(i - 1);
if (i + 2 < a.length && !visited[i + 2] && edge(a, i, i + 2))
toVisit.add(i + 2);
if (i + 1 < a.length && !visited[i + 1] && edge(a, i, i + 1))
toVisit.add(i + 1);
}
return visited;
}Context
StackExchange Code Review Q#82801, answer score: 2
Revisions (0)
No revisions yet.