Java codility Frog-River-One
Я пытаюсь решить упражнение Java на веб-странице Codility.
Ниже приведена ссылка на упомянутое упражнение и мое решение.
https://codility.com/demo/results/demoH5GMV3-PV8
Кто-нибудь может сказать, что я могу исправить в своем коде, чтобы улучшить оценку?
На всякий случай вот описание задачи:
Маленькая лягушка хочет добраться до другой стороны реки. В настоящее время лягушка находится в положении 0 и хочет попасть в положение X. Листья падают с дерева на поверхность реки.
Вам предоставляется непустой нуль-индексированный массив A, состоящий из N целых чисел, представляющих падающие листья. A [K] представляет положение, в котором один лист падает в момент времени K, измеряемый в минутах.
Цель состоит в том, чтобы найти самое раннее время, когда лягушка может прыгнуть на другую сторону реки. Лягушка может пересекаться только тогда, когда листья появляются в каждом положении через реку от 1 до X.
Например, вам присваивается целое число X = 5 и массив A, для которых:
A[0] = 1
A[1] = 3
A[2] = 1
A[3] = 4
A[4] = 2
A[5] = 3
A[6] = 5
A[7] = 4
В минуту 6 лист попадает в положение 5. Это самое раннее время, когда листья появляются в каждом положении через реку.
Напишите функцию:
class Solution { public int solution(int X, int[] A); }
что, учитывая непустой нуль-индексированный массив A, состоящий из N целых чисел и целого X, возвращает самое раннее время, когда лягушка может перепрыгнуть на другую сторону реки.
Если лягушка никогда не сможет прыгнуть на другую сторону реки, функция должна вернуть -1.
Например, если заданы X = 5 и массив A такие, что:
A[0] = 1
A[1] = 3
A[2] = 1
A[3] = 4
A[4] = 2
A[5] = 3
A[6] = 5
A[7] = 4
функция должна возвращать 6, как объяснялось выше. Предположим, что:
N and X are integers within the range [1..100,000];
each element of array A is an integer within the range [1..X].
Сложность:
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).
Элементы входных массивов могут быть изменены.
И вот мое решение:
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;
}
}
Ответы
Ответ 1
Вы используете arrayList.contains
внутри цикла, который излишне пересекает весь список.
Вот мое решение (я написал это некоторое время назад, но я считаю, что он оценивает 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;
}
Ответ 2
Вот мое решение. Он получил меня 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]);
}
Ответ 3
Решение Java с использованием Sets (Framework Collections) Получено 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;
}
Ответ 4
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;
}
Ответ 5
Лучшим подходом было бы использовать Set
, потому что он только добавляет уникальные значения в список. Просто добавляйте значения к Set
и декременту X
каждый раз при добавлении нового значения (Set#add()
возвращает true
, если значение добавлено, false
в противном случае);
взгляните,
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;
}
не забудьте импортировать,
import java.util.HashSet;
import java.util.Set;
Ответ 6
Простое решение 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;
}
Ответ 7
Вот мое решение.
Это не идеально, но это достаточно хорошо, чтобы набрать 100/100.
(Я думаю, что он не должен был проходить тест с большим A и маленьким X)
В любом случае он заполняет новый массив counter
каждым листом, который падает
имеет размер X, потому что мне не нужны листья, которые падают дальше X, поэтому блок try-catch.
ПОСЛЕ X листьев упал (потому что это минимальное количество листьев) Я начинаю проверять, есть ли у меня полный путь - я проверяю, что каждый int в count больше 0.
Если это так, я возвращаю i, иначе я сломаюсь и попробую еще раз.
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;
}
Ответ 8
Здесь мое решение с 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;
}
Ответ 9
Здесь мое решение, набравшее 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;
}
}
Ответ 10
Просто попробовал эту проблему, и вот мое решение. В принципе, я просто объявил массив, размер которого равен позиции X. Затем я объявил счетчик, чтобы отслеживать, попали ли нужные листья в определенные места. Цикл завершается, когда эти листья были выполнены, а если нет, возвращает -1 в соответствии с инструкциями.
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;
}
}
Он получил оценку 100/100, но я не уверен в ее производительности. Я все еще новичок, когда дело доходит до программирования, поэтому, если кто-то может критиковать код, я был бы благодарен.
Ответ 11
Возможно, это не идеально, но просто. Просто сделал счетчик Array, чтобы отслеживать нужные "листья" и проверять на каждой итерации, если путь был завершен. Получил 100/100 и 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;
}
Ответ 12
Это мое решение. Я думаю, это очень просто. Он получает 100/100 на удобочитаемость.
set.contains() позволяет мне исключить дублируемую позицию из таблицы.
Результат первого цикла дает нам ожидаемую сумму. Во втором цикле мы получаем сумму входных значений.
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;
}
}
Ответ 13
Вот что у меня на С#. Вероятно, он может быть реорганизован.
Мы отбрасываем числа, большие, чем X, где мы хотим остановиться, а затем добавляем числа в массив, если они еще не добавлены.
Когда счетчик списка достигнет ожидаемого числа, X, верните результат. 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;
Ответ 14
Ваш алгоритм совершенен, за исключением кода ниже
Ваш код возвращает значение, только если список [iii] соответствует searchValue.
Алгоритм должен быть скорректирован таким образом, чтобы он возвращал значение, если сумма == 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;
}
}
Я думаю, вам нужно также проверить производительность. Я просто обеспечил выход только
Ответ 15
Это решение, которое я опубликовал сегодня, дал 100% на кодовости, но уважительно @rafalio отвечает, что он требует в K раз меньше памяти
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);
}
}
Ответ 16
Это мое решение, оно получило меня 100/100 и 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());
}
Ответ 17
ниже - мое решение. Я в основном создал набор, который позволяет только uniques, а затем пройти через массив и добавить каждый элемент для установки и сохранить счетчик, чтобы получить сумму набора, а затем использовать формулу суммы последовательных чисел, после чего я получил 100%. Примечание: если вы добавите набор, используя java 8 stream api, решение становится квадратичным, и вы получите% 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;
}
Ответ 18
Это мое решение
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))
Ответ 19
На самом деле я переписал это упражнение, не видя своего последнего ответа, и придумал другое решение 100/100 и 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;
}
Мне больше нравится этот, потому что он еще проще.
Ответ 20
Это мое решение. Он использует 3 петли, но является постоянным временем и получает 100/100 от совместимости.
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;
}
}
Ответ 21
Короткий и сладкий код C++. Получает идеальный 100%... Барабан ролл... ![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;
}
Ответ 22
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;
}
}
Ответ 23
Мое решение JavaScript, получившее 100 по всем направлениям. Поскольку предполагается, что числа находятся в диапазоне ширины реки, подойдет просто сохранение логических значений во временном массиве, который можно проверить на наличие дубликатов. Затем, как только вы наберете столько чисел, сколько и количества X, вы знаете, что у вас есть все листья, необходимые для пересечения.
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;
}
Ответ 24
Это зацикливает массив A и вставляет данные в массив B (1) в каждую позицию, на которую указывает содержимое в A..
Если A [0] = 4, то при B [4-1] = 1 делайте это до тех пор, пока var = X.
public static int bestSolution(int X, int[] A) {
int[] B = new int[X];
int var = 0;
for (int i = 0; i < A.length; i++) {
int content = A[i];
if (B[content - 1] == 0) {
B[content - 1] = 1;
var++;
}
if(var == X){
return i;
}
}
return -1;
}
Ответ 25
private static int FrogRiverOne(int X, int[] A)
{
HashSet<int> occ = new HashSet<int>();
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= X)
{
occ.Add(A[i]);
}
if (occ.Count == X)
return i;
}
return -1;}