Count the minimum number of jumps required for a frog to get to the other side of a river

11,261

Solution 1

You can apply knapsack algorithms to solve this problem. In my solution I precomputed fibonacci numbers. And applied knapsack algorithm to solve it. It contains duplicate code, did not have much time to refactor it. Online ide with the same code is in repl

import java.util.*;
class Main {

public static int solution(int[] A) {

    int N = A.length;
    int inf=1000000;
    int[] fibs={1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025};
    int[] moves = new int[N+1];
     for(int i=0; i<=N; i++){
        moves[i]=inf;
     }
    for(int i=0; i<fibs.length; i++){
        if(fibs[i]-1<N && A[fibs[i]-1]==1){
            moves[ fibs[i]-1 ] = 1;
        }
        if(fibs[i]-1==N){
           moves[N] = 1;
        }
    }

    for(int i=0; i<N; i++){
        if(A[i]==1)
        for(int j=0; j<fibs.length; j++){
            if(i-fibs[j]>=0 && moves[i-fibs[j]]!=inf && moves[i]>moves[i-fibs[j]]+1){
                moves[i]=moves[i-fibs[j]]+1;
            }                
        }
         System.out.println(i + " => " + moves[i]);
    }

     for(int i=N; i<=N; i++){
        for(int j=0; j<fibs.length; j++){
            if(i-fibs[j]>=0 && moves[i-fibs[j]]!=inf && moves[i]>moves[i-fibs[j]]+1){
                moves[i]=moves[i-fibs[j]]+1;
            }                
        }
         System.out.println(i + " => " + moves[i]);
    }

    if(moves[N]==inf) return -1;
    return moves[N];
}

public static void main(String[] args) {

int[] A = new int[4];

A[0] = 0;
A[1] = 0;
A[2] = 0;
A[3] = 0;
System.out.println(solution(A));
 }
}

Solution 2

Got 100% with simple BFS:

public class Jump {
    int pos;
    int move;
    public Jump(int pos, int move) {
        this.pos = pos;
        this.move = move;
    }
}

public int solution(int[] A) {

    int n = A.length;
    List < Integer > fibs = fibArray(n + 1);
    Queue < Jump > positions = new LinkedList < Jump > ();
    boolean[] visited = new boolean[n + 1];

    if (A.length <= 2)
        return 1;

    for (int i = 0; i < fibs.size(); i++) {
        int initPos = fibs.get(i) - 1;
        if (A[initPos] == 0)
            continue;
        positions.add(new Jump(initPos, 1));
        visited[initPos] = true;
    }

    while (!positions.isEmpty()) {
        Jump jump = positions.remove();
        for (int j = fibs.size() - 1; j >= 0; j--) {
            int nextPos = jump.pos + fibs.get(j);
            if (nextPos == n)
                return jump.move + 1;
            else if (nextPos < n && A[nextPos] == 1 && !visited[nextPos]) {
                positions.add(new Jump(nextPos, jump.move + 1));
                visited[nextPos] = true;
            }
        }
    }


    return -1;
}


private List < Integer > fibArray(int n) {
    List < Integer > fibs = new ArrayList < > ();
    fibs.add(1);
    fibs.add(2);
    while (fibs.get(fibs.size() - 1) + fibs.get(fibs.size() - 2) <= n) {
        fibs.add(fibs.get(fibs.size() - 1) + fibs.get(fibs.size() - 2));
    }
    return fibs;
}

Solution 3

Javascript 100%

function solution(A) {
    function fibonacciUntilNumber(n) {
        const fib = [0,1];
        while (true) {
            let newFib = fib[fib.length - 1] + fib[fib.length - 2];
            if (newFib > n) {
                break;
            }
            fib.push(newFib);
        }
        return fib.slice(2);
    }
    A.push(1);
    const fibSet = fibonacciUntilNumber(A.length);
    if (fibSet.includes(A.length)) return 1;
    const reachable = Array.from({length: A.length}, () => -1);

    fibSet.forEach(jump => {
        if (A[jump - 1] === 1) {
            reachable[jump - 1] = 1;
        }
    })

    for (let index = 0; index < A.length; index++) {
        if (A[index] === 0 || reachable[index] > 0) {
            continue;
        }
        let minValue = 100005;
        for (let jump of fibSet) {
            let previousIndex = index - jump;
            if (previousIndex < 0) {
                break;
            }
            if (reachable[previousIndex] > 0 && minValue > reachable[previousIndex]) {
                minValue = reachable[previousIndex];
            }
        }
        if (minValue !== 100005) {
            reachable[index] = minValue + 1;
        }
    }
    return reachable[A.length - 1];
}

Solution 4

Got 100%- solution in C.

typedef struct state {
    int pos;
    int step;
}state;
int solution(int A[], int N) {

    int f1 = 0;
    int f2 = 1;
    int count = 2;
    // precalculating count of maximum possible fibonacci numbers to allocate array in next loop. since this is C language we do not have flexible dynamic structure as in C++
    while(1)
    {
        int f3 =  f2 + f1;
        if(f3 > N)
            break;
        f1 = f2;
        f2 = f3;
        ++count;
    }
    int fib[count+1];
    fib[0] = 0;
    fib[1] = 1;
    int i = 2;
    // calculating fibonacci numbers in array
    while(1)
    {
        fib[i] =  fib[i-1] + fib[i-2];
        if(fib[i] > N)
            break;
        ++i;
    }
    // reversing the fibonacci numbers because we need to create minumum jump counts with bigger jumps
    for(int j = 0, k = count; j < count/2; j++,k--)
    {
        int t = fib[j];
        fib[j] = fib[k];
        fib[k] = t;
    }
    state q[N];
    int front = 0 ;
    int rear = 0;
    q[0].pos = -1;
    q[0].step = 0;
    int que_s = 1;
    while(que_s > 0)
    {
        state s =  q[front];
        front++;
        que_s--;
        for(int i = 0; i <= count; i++)
        {
            int nextpo = s.pos + fib[i];
            if(nextpo == N)
            {
                return s.step+1;
            }
            else if(nextpo > N || nextpo < 0 || A[nextpo] == 0){
           
                continue;  
            }
            else
            {
                q[++rear].pos = nextpo;
                q[rear].step = s.step + 1;
                que_s++;
                A[nextpo] = 0;
            }
        }
    }
    return -1;
}

Solution 5

Python 100% answer.

For me the easiest solution was to locate all leaves within one fib jump of -1. Then consider each of these leaves to be index[0] and find all jumps from there. Each generation or jump is recorded in a set until a generation contains len(A) or no more jumps can be found.

def gen_fib(n):
    fn = [0,1]
    i = 2
    s = 2
    while s < n:
        s = fn[i-2] + fn[i-1]
        fn.append(s)
        i+=1
    return fn

def new_paths(A, n, last_pos, fn):
    """
    Given an array A of len n.
    From index last_pos which numbers in fn jump to a leaf?
    returns list: set of indexes with leaves.
    """
    paths = []
    for f in fn:
        new_pos = last_pos + f
        if new_pos == n or (new_pos < n and A[new_pos]):
            paths.append(new_pos)
    return path

def solution(A):
    n = len(A)
    if n < 3:
        return 1

    # A.append(1) # mark final jump
    fn = sorted(gen_fib(100000)[2:]) # Fib numbers with 0, 1, 1, 2..  clipped to just 1, 2..
    # print(fn)
    paths = set([-1]) # locate all the leaves that are one fib jump from the start position.

    jump = 1
    while True:
        # Considering each of the previous jump positions - How many leaves from there are one fib jump away
        paths =  set([idx for pos in paths for idx in new_paths(A, n, pos, fn)])

        # no new jumps means game over!
        if not paths:
            break

        # If there was a result in the new jumps record that
        if n in paths:
            return jump
            
        jump += 1

    return -1

https://app.codility.com/demo/results/training4GQV8Y-9ES/

https://github.com/niall-oc/things/blob/master/codility/fib_frog.py

Share:
11,261
Arefe
Author by

Arefe

Updated on June 21, 2022

Comments

  • Arefe
    Arefe almost 2 years

    I work with a Codility problem provided below,

    The Fibonacci sequence is defined using the following recursive formula:

    F(0) = 0
    F(1) = 1
    F(M) = F(M - 1) + F(M - 2) if M >= 2
    

    A small frog wants to get to the other side of a river. The frog is initially located at one bank of the river (position −1) and wants to get to the other bank (position N). The frog can jump over any distance F(K), where F(K) is the K-th Fibonacci number. Luckily, there are many leaves on the river, and the frog can jump between the leaves, but only in the direction of the bank at position N.

    The leaves on the river are represented in an array A consisting of N integers. Consecutive elements of array A represent consecutive positions from 0 to N − 1 on the river. Array A contains only 0s and/or 1s:

    0 represents a position without a leaf; 1 represents a position containing a leaf. The goal is to count the minimum number of jumps in which the frog can get to the other side of the river (from position −1 to position N). The frog can jump between positions −1 and N (the banks of the river) and every position containing a leaf.

    For example, consider array A such that:

    A[0] = 0
    A[1] = 0
    A[2] = 0
    A[3] = 1
    A[4] = 1
    A[5] = 0
    A[6] = 1
    A[7] = 0
    A[8] = 0
    A[9] = 0
    A[10] = 0
    

    The frog can make three jumps of length F(5) = 5, F(3) = 2 and F(5) = 5.

    Write a function:

    class Solution { public int solution(int[] A); }
    

    that, given an array A consisting of N integers, returns the minimum number of jumps by which the frog can get to the other side of the river. If the frog cannot reach the other side of the river, the function should return −1.

    For example, given:

    A[0] = 0
    A[1] = 0
    A[2] = 0
    A[3] = 1
    A[4] = 1
    A[5] = 0
    A[6] = 1
    A[7] = 0
    A[8] = 0
    A[9] = 0
    A[10] = 0
    

    the function should return 3, as explained above.

    Assume that:

    N is an integer within the range [0..100,000]; each element of array A is an integer that can have one of the following values: 0, 1. Complexity:

    expected worst-case time complexity is O(N*log(N)); expected worst-case space complexity is O(N) (not counting the storage required for input arguments).

    I wrote the following solution,

    class Solution {
        private class Jump {
            int position;
            int number;
    
            public int getPosition() {
                return position;
            }
    
            public int getNumber() {
                return number;
            }
    
            public Jump(int pos, int number) {
                this.position = pos;
                this.number = number;
            }
        }
    
        public int solution(int[] A) {
    
            int N = A.length;
    
            List<Integer> fibs = getFibonacciNumbers(N + 1);
    
            Stack<Jump> jumps = new Stack<>();
            jumps.push(new Jump(-1, 0));
    
            boolean[] visited = new boolean[N];
    
            while (!jumps.isEmpty()) {
    
                Jump jump = jumps.pop();
    
                int position = jump.getPosition();
                int number = jump.getNumber();
    
                for (int fib : fibs) {
    
                    if (position + fib > N) {
                        break;
                    } else if (position + fib == N) {
                        return number + 1;
                    } else if (!visited[position + fib] && A[position + fib] == 1) {
    
                        visited[position + fib] = true;
                        jumps.add(new Jump(position + fib, number + 1));
                    }
                }
            }
    
            return -1;
        }
    
    
        private List<Integer> getFibonacciNumbers(int N) {
    
            List<Integer> list = new ArrayList<>();
    
            for (int i = 0; i < 2; i++) {
                list.add(i);
            }
    
            int i = 2;
    
            while (list.get(list.size() - 1) <= N) {
    
                list.add(i, (list.get(i - 1) + list.get(i - 2)));
                i++;
            }
    
            for (i = 0; i < 2; i++) {
                list.remove(i);
            }
    
            return list;
        }
    
    
    
    
        public static void main(String[] args) {
    
        int[] A = new int[11];
    
        A[0] = 0;
        A[1] = 0;
        A[2] = 0;
        A[3] = 1;
        A[4] = 1;
        A[5] = 0;
        A[6] = 1;
        A[7] = 0;
        A[8] = 0;
        A[9] = 0;
        A[10] = 0;
    
        System.out.println(solution(A));
       }
    }
    

    However, while the correctness seems good, the performance is not high enough. Is there a bug in the code and how do I improve the performance?

    enter image description here