'java codility Frog-River-One

I have been trying to solve a Java exercise on a Codility web page.

Below is the link to the mentioned exercise and my solution.

https://codility.com/demo/results/demoH5GMV3-PV8

Can anyone tell what can I correct in my code in order to improve the score?

Just in case here is the task description:

A small frog wants to get to the other side of a river. The frog is currently located at position 0, and wants to get to position X. Leaves fall from a tree onto the surface of the river.

You are given a non-empty zero-indexed array A consisting of N integers representing the falling leaves. A[K] represents the position where one leaf falls at time K, measured in minutes.

The goal is to find the earliest time when the frog can jump to the other side of the river. The frog can cross only when leaves appear at every position across the river from 1 to X.

For example, you are given integer X = 5 and array A such that:

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

In minute 6, a leaf falls into position 5. This is the earliest time when leaves appear in every position across the river.

Write a function:

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

that, given a non-empty zero-indexed array A consisting of N integers and integer X, returns the earliest time when the frog can jump to the other side of the river.

If the frog is never able to jump to the other side of the river, the function should return −1.

For example, given X = 5 and array A such that:

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

the function should return 6, as explained above. Assume that:

N and X are integers within the range [1..100,000];
each element of array A is an integer within the range [1..X].

Complexity:

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

Elements of input arrays can be modified.

And here is my solution:

import java.util.ArrayList;
import java.util.List;

class Solution {

    public int solution(int X, int[] A) {
        int list[] = A;
        int sum = 0;
        int searchedValue = X;

        List<Integer> arrayList = new ArrayList<Integer>();

        for (int iii = 0; iii < list.length; iii++) {

            if (list[iii] <= searchedValue && !arrayList.contains(list[iii])) {
                sum += list[iii];
                arrayList.add(list[iii]);
            }
            if (list[iii] == searchedValue) {
                if (sum == searchedValue * (searchedValue + 1) / 2) {
                    return iii;
                }
            }
        }
        return -1;
    }
}


Solution 1:[1]

You are using arrayList.contains inside a loop, which will traverse the whole list unnecessarily.

Here is my solution (I wrote it some time ago, but I believe it scores 100/100):

    public int frog(int X, int[] A) {
        int steps = X;
        boolean[] bitmap = new boolean[steps+1];
        for(int i = 0; i < A.length; i++){
            if(!bitmap[A[i]]){
                bitmap[A[i]] = true;
                steps--;
                if(steps == 0) return i;
            }

        }
        return -1;
    }

Solution 2:[2]

Here is my solution. It got me 100/100:

public int solution(int X, int[] A)
{
     int[] B = A.Distinct().ToArray();
     return (B.Length != X) ? -1 : Array.IndexOf<int>(A, B[B.Length - 1]);
}

Solution 3:[3]

100/100

public static int solution (int X, int[] A){

    int[]counter = new int[X+1];
    int ans = -1;
    int x = 0;

    for (int i=0; i<A.length; i++){
        if (counter[A[i]] == 0){
            counter[A[i]] = A[i];
            x += 1;
            if (x == X){
                return i;
            }
        } 
    }

    return ans;
}

Solution 4:[4]

A Java solution using Sets (Collections Framework) Got a 100%

import java.util.Set;
import java.util.TreeSet;
public class Froggy {
    public static int solution(int X, int[] A){
    int steps=-1;
    Set<Integer> values = new TreeSet<Integer>();
    for(int i=0; i<A.length;i++){
        if(A[i]<=X){
            values.add(A[i]);
        }
        if(values.size()==X){
            steps=i;
            break;
        }
    }
        return steps;
    }

Solution 5:[5]

Better approach would be to use Set, because it only adds unique values to the list. Just add values to the Set and decrement X every time a new value is added, (Set#add() returns true if value is added, false otherwise); have a look,

public static int solution(int X, int[] A) {
    Set<Integer> values = new HashSet<Integer>();
    for (int i = 0; i < A.length; i++) {
        if (values.add(A[i])) X--; 
        if (X == 0) return i;
    }
    return -1;
}

do not forget to import,

import java.util.HashSet;
import java.util.Set;

Solution 6:[6]

Here's my solution, scored 100/100:

import java.util.HashSet;

class Solution {
    public int solution(int X, int[] A) {
        HashSet<Integer> hset = new HashSet<Integer>();

        for (int i = 0 ; i < A.length; i++) {
            if (A[i] <= X)
               hset.add(A[i]);   
            if (hset.size() == X)
               return i;
        }

        return -1;
    }
}

Solution 7:[7]

Simple solution 100%

public int solution(final int X, final int[] A) {

Set<Integer> emptyPosition = new HashSet<Integer>();

for (int i = 1; i <= X; i++) {
  emptyPosition.add(i);
}
// Once all the numbers are covered for position, that would be the
// moment when the frog will jump
for (int i = 0; i < A.length; i++) {
  emptyPosition.remove(A[i]);
  if (emptyPosition.size() == 0) {
    return i;
  }
}
return -1;
}

Solution 8:[8]

Here's my solution. It isn't perfect, but it's good enough to score 100/100. (I think that it shouldn't have passed a test with a big A and small X)

Anyway, it fills a new counter array with each leaf that falls

counter has the size of X because I don't care for leafs that fall farther than X, therefore the try-catch block.

AFTER X leafs fell (because it's the minimum amount of leafs) I begin checking whether I have a complete way - I'm checking that every int in count is greater than 0. If so, I return i, else I break and try again.

public static int solution(int X, int[] A){
    int[] count = new int[X];
    for (int i = 0; i < A.length; i++){
        try{
            count[A[i]-1]++;
        } catch (ArrayIndexOutOfBoundsException e){ }
        if (i >= X - 1){
            for (int j = 0; j< count.length; j++){
                if (count[j] == 0){
                    break;
                }
                if (j == count.length - 1){
                    return i;
                }
            }
        }
    }
    return -1;
}

Solution 9:[9]

Here's my solution with 100 / 100.

public int solution(int X, int[] A) {
    int len = A.length;
    if (X > len) {
        return -1;
    }
    int[] isFilled = new int[X];
    int jumped = 0;
    Arrays.fill(isFilled, 0);
    for (int i = 0; i < len; i++) {
        int x = A[i];
        if (x <= X) {
            if (isFilled[x - 1] == 0) {
                isFilled[x - 1] = 1;
                jumped += 1;
                if (jumped == X) {
                    return i;
                }
            }
        }
    }

    return -1;
}

Solution 10:[10]

Here's what I have in C#. It can probably still be refactored. We throw away numbers greater than X, which is where we want to stop, and then we add numbers to an array if they haven't already been added. When the count of the list has reached the expected number, X, then return the result. 100%

        var tempArray = new int[X+1];
        var totalNumbers = 0;
        for (int i = 0; i < A.Length; i++)
        {
            if (A[i] > X || tempArray.ElementAt(A[i]) != 0)
                continue;
            tempArray[A[i]] = A[i];
            totalNumbers++;

            if (totalNumbers == X)
                return i;
        }

        return -1;

Solution 11:[11]

below is my solution. I basically created a set which allows uniques only and then go through the array and add every element to set and keep a counter to get the sum of the set and then using the sum formula of consecutive numbers then I got 100% . Note : if you add up the set using java 8 stream api the solution is becoming quadratic and you get %56 .

public static int solution2(int X, int[] A) {

    long sum = X * (X + 1) / 2;
    Set<Integer> set = new HashSet<Integer>();
    int setSum = 0;

    for (int i = 0; i < A.length; i++) {
        if (set.add(A[i]))
            setSum += A[i];

        if (setSum == sum) {
            return i;
        }

    }

    return -1;
}

Solution 12:[12]

My JavaScript solution that got 100 across the board. Since the numbers are assumed to be in the range of the river width, simply storing booleans in a temporary array that can be checked against duplicates will do. Then, once you have amassed as many numbers as the quantity X, you know you have all the leaves necessary to cross.

function solution(X, A) {
    covered = 0;
    tempArray = [];
    for (let i = 0; i < A.length; i++) {
        if (!tempArray[A[i]]) {
            tempArray[A[i]] = true;
            covered++
            if(covered === X) return i;
        }
    }
    return -1;
}

Solution 13:[13]

Here is my answer in Python:

def solution(X, A):
    # write your code in Python 3.6
    values = set()
    for i in range (len(A)):
        if A[i]<=X :
            values.add(A[i])
        if len(values)==X:
            return i
    return -1

Solution 14:[14]

Just tried this problem as well and here is my solution. Basically, I just declared an array whose size is equal to position X. Then, I declared a counter to monitor if the necessary leaves have fallen at the particular spots. The loop exits when these leaves have been met and if not, returns -1 as instructed.

class Solution {
    public int solution(int X, int[] A) {
        int size = A.length;
        int[] check = new int[X];
        int cmp = 0;
        int time = -1;

        for (int x = 0; x < size; x++) {
            int temp = A[x];
            if (temp <= X) {
                if (check[temp-1] > 0) {
                    continue;
                }
                check[temp - 1]++;
                cmp++;
            }

            if ( cmp == X) {
                time = x;
                break;
            }
        }

        return time;
    }
}

It got a 100/100 on the evaluation but I'm not too sure of its performance. I am still a beginner when it comes to programming so if anybody can critique the code, I would be grateful.

Solution 15:[15]

Maybe it is not perfect but its straightforward. Just made a counter Array to track the needed "leaves" and verified on each iteration if the path was complete. Got me 100/100 and O(N).

    public static int frogRiver(int X, int[] A)
    {
        int leaves = A.Length;
        int[] counter = new int[X + 1];
        int stepsAvailForTravel = 0;

        for(int i = 0; i < leaves; i++)
        {
            //we won't get to that leaf anyway so we shouldnt count it,
            if (A[i] > X)
            {
                continue;
            } 
            else
            {
                //first hit!, keep a count of the available leaves to jump
                if (counter[A[i]] == 0)
                    stepsAvailForTravel++;

                counter[A[i]]++;

            }
            //We did it!!
            if (stepsAvailForTravel == X)
            {
                return i;
            }
        }

        return -1;

    }

Solution 16:[16]

This is my solution. I think it's very simple. It gets 100/100 on codibility. set.contains() let me eliminate duplicate position from table. The result of first loop get us expected sum. In the second loop we get sum of input values.

class Solution {
    public int solution(int X, int[] A) {

        Set<Integer> set = new HashSet<Integer>();
        int sum1 = 0, sum2 = 0;

        for (int i = 0; i <= X; i++){
            sum1 += i;       
        }

        for (int i = 0; i < A.length; i++){
            if (set.contains(A[i])) continue;
            set.add(A[i]);
            sum2 += A[i];
            if (sum1 == sum2) return i;
        }        
        return -1;
    }
}

Solution 17:[17]

Your algorithm is perfect except below code Your code returns value only if list[iii] matches with searchedValue.

The algorithm must be corrected in such a way that, it returns the value if sum == n * ( n + 1) / 2.

import java.util.ArrayList;
import java.util.List;
class Solution {
    public int solution(int X, int[] A) {
        int list[] = A;
        int sum = 0;
        int searchedValue = X;
        int sumV = searchedValue * (searchedValue + 1) / 2;   
        List<Integer> arrayList = new ArrayList<Integer>();
        for (int iii = 0; iii < list.length; iii++) {
            if (list[iii] <= searchedValue && !arrayList.contains(list[iii])) {
                sum += list[iii];
                if (sum == sumV) {
                    return iii;
                }
                arrayList.add(list[iii]);
            }
        }
        return -1;
    }
}

I think you need to check the performance as well. I just ensured the output only

Solution 18:[18]

This solution I've posted today gave 100% on codility, but respectivly @rafalio 's answer it requires K times less memory

public class Solution {

    private static final int ARRAY_SIZE_LOWER = 1;
    private static final int ARRAY_SIZE_UPPER = 100000;
    private static final int NUMBER_LOWER = ARRAY_SIZE_LOWER;
    private static final int NUMBER_UPPER = ARRAY_SIZE_UPPER;

    public static class Set {

        final long[] buckets;

        public Set(int size) {
            this.buckets = new long[(size % 64 == 0 ? (size/64) : (size/64) + 1)];
        }

        /**
         * number should be greater than zero
         * @param number
         */
        public void put(int number) {
            buckets[getBucketindex(number)] |= getFlag(number); 
        }

        public boolean contains(int number) {
            long flag = getFlag(number);
            // check if flag is stored
            return (buckets[getBucketindex(number)] & flag) == flag;
        }

        private int getBucketindex(int number) {
            if (number <= 64) {
                return 0;
            } else if (number <= 128) {
                return 1;
            } else if (number <= 192) {
                return 2;
            } else if (number <= 256) {
                return 3;
            } else if (number <= 320) {
                return 4;
            } else if (number <= 384) {
                return 5;
            } else 
                return (number % 64 == 0 ? (number/64) : (number/64) + 1) - 1;
        }

        private long getFlag(int number) {
            if (number <= 64) {
                return 1L << number;
            } else
                return 1L << (number % 64);
        }
    }

    public static final int solution(final int X, final int[] A) {
        if (A.length < ARRAY_SIZE_LOWER || A.length > ARRAY_SIZE_UPPER) {
            throw new RuntimeException("Array size out of bounds");
        }
        Set set = new Set(X);
        int ai;
        int counter = X;
        final int NUMBER_REAL_UPPER = min(NUMBER_UPPER, X);
        for (int i = 0 ; i < A.length; i++) {
            if ((ai = A[i]) < NUMBER_LOWER || ai > NUMBER_REAL_UPPER) {
                throw new RuntimeException("Number out of bounds");
            } else if (ai <= X && !set.contains(ai)) {
                counter--;
                if (counter == 0) {
                    return i;
                }
                set.put(ai);
            }
        }
        return -1;
    }

    private static int min(int x, int y) {
        return (x < y ? x : y);
    }
}

Solution 19:[19]

This is my solution it got me 100/100 and O(N).

public int solution(int X, int[] A) {
    Map<Integer, Integer> leaves = new HashMap<>();

    for (int i = A.length - 1; i >= 0 ; i--)
    {
        leaves.put(A[i] - 1, i);
    }

    return leaves.size() != X ? -1 : Collections.max(leaves.values());
}

Solution 20:[20]

This is my solution

public func FrogRiverOne(_ X : Int, _ A : inout [Int]) -> Int {

    var B = [Int](repeating: 0, count: X+1)

    for i in 0..<A.count {
        if B[A[i]] == 0 {
            B[A[i]] = i+1
        }
    }

    var time = 0

    for i in 1...X {
        if( B[i] == 0 ) {
            return -1
        } else {
            time = max(time, B[i])
        }
    }

    return time-1
}

A = [1,2,1,4,2,3,5,4]
print("FrogRiverOne: ", FrogRiverOne(5, &A))

Solution 21:[21]

Actually I re-wrote this exercise without seeing my last answer and came up with another solution 100/100 and O(N).

public int solution(int X, int[] A) {
    Set<Integer> leaves = new HashSet<>();

    for(int i=0; i < A.length; i++) {
        leaves.add(A[i]);

        if (leaves.contains(X) && leaves.size() == X)  return i; 
    }

    return -1;
}

I like this one better because it is even simpler.

Solution 22:[22]

This one works good on codality 100% out of 100%. It's very similar to the marker array above but uses a map:


  public int solution(int X, int[] A) {
    int index = -1;

    Map<Integer, Integer> map = new HashMap();
    for (int i = 0; i < A.length; i++) {
      if (!map.containsKey(A[i])) {
        map.put(A[i], A[i]);
        X--;
        if (X == 0) {index = i;break;}
      }
    }

    return index;
  }

Solution 23:[23]

%100 with js

function solution(X, A) {

  let leafSet = new Set();

  for (let i = 0; i < A.length; i += 1) {

    if(A[i] <= 0) 
        continue;

    if (A[i] <= X )
        leafSet.add(A[i]); 


    if (leafSet.size == X)
      return i;

  }

  return -1;
}

Solution 24:[24]

With JavaScript following solution got 100/100.

Detected time complexity: O(N)

function solution(X, A) {
    let leaves = new Set();

    for (let i = 0; i < A.length; i++) {
        if (A[i] <= X) {
            leaves.add(A[i])
            if (leaves.size == X) {
                return i;
            }
        }
    }
    return -1;    
}

Solution 25:[25]

100% Solution using Javascript.

enter image description here

function solution(X, A) {
    if (A.length === 0) return -1
    if (A.length < X) return -1


    let steps = X
    const leaves = {}
    for (let i = 0; i < A.length; i++) {
        if (!leaves[A[i]]) {
            leaves[A[i]] = true
            steps--
        }

        if (steps === 0) {
            return i
        }
    }

    return -1
}

Solution 26:[26]

C# Solution with 100% score:

using System;
using System.Collections.Generic;

class Solution {
    public int solution(int X, int[] A) {
        // go through the array
        // fill a hashset, until the size of hashset is X
        var set = new HashSet<int>();
        int i = 0;
        foreach (var a in A)
        {
            if (a <= X)
            {
                set.Add(a);
            }
            if (set.Count == X)
            {
                return i;
            }
            i++;
        }
        return -1;
    }
}

Solution 27:[27]

https://app.codility.com/demo/results/trainingXE7QFJ-TZ7/

I have a very simple solution (100% / 100%) using HashSet. Lots of people check unnecessarily whether the Value is less than or equal to X. This task cannot be otherwise.

public static int solution(int X, int[] A) {
    Set<Integer> availableFields = new HashSet<>();

    for (int i = 0; i < A.length; i++) {
        availableFields.add(A[i]);
        if (availableFields.size() == X){
            return i;
        }
    }

    return -1;
}

Solution 28:[28]

This is my solution. It uses 3 loops but is constant time and gets 100/100 on codibility.

class FrogLeap
{
    internal int solution(int X, int[] A)
    {
        int result = -1;
        long max = -1;
        var B = new int[X + 1];

        //initialize all entries in B array with -1
        for (int i = 0; i <= X; i++)
        {
            B[i] = -1;
        }

        //Go through A and update B with the location where that value appeared
        for (int i = 0; i < A.Length; i++)
        {
           if( B[A[i]] ==-1)//only update if still -1
            B[A[i]] = i;
        }

        //start from 1 because 0 is not valid
        for (int i = 1; i <= X; i++)
        {
            if (B[i] == -1)
                return -1;
            //The maxValue here is the earliest time we can jump over
            if (max < B[i])
                max = B[i];
        }

        result = (int)max;
        return result;
    }
}

Solution 29:[29]

Short and sweet C++ code. Gets perfect 100%... Drum roll ... enter image description here

#include <set>
int solution(int X, vector<int> &A) {
    set<int> final;
    for(unsigned int i =0; i< A.size(); i++){
        final.insert(A[i]);
        if(final.size() == X) return i;
    }
    return -1;
}

Solution 30:[30]

import java.util.Set;
import java.util.HashSet;
// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");

class Solution {
    public int solution(int X, int[] A) {
     Set<Integer> positionsCovered = new HashSet<Integer>(); 
//Set covering the leaves fallen to keep track of the distance to destination   

        if(X == 1)
             return 0 ;
       int position = 0;     
       for(int i = 0; i < A.length -1 ;i++ ) {       
           if(A[i] <= X && A[i] > 1 && positionsCovered.size() < (X-1)) { 
      //X-1 as we start from 1
               positionsCovered.add(A[i]);
           }
           if(positionsCovered.size()== (X-1)) {
               position = i ;
            break;
           }
       }         
        return position != 0 ? position : -1;
    }
}