Алгоритм линейного времени для минимального количества прыжков, необходимых для достижения цели

Задача: Минимальное количество прыжков для достижения цели

Учитывая массив целых чисел, где каждый элемент представляет максимальное количество шагов, которые могут быть сделаны из этого элемента. Напишите функцию, чтобы вернуть минимальное количество переходов для достижения конца массива (начиная с первого элемента). Если элемент равен 0, мы не можем перемещаться по этому элементу.

Пример:

Вход: arr [] = {1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9} Выход: 3 (1- > 3 → 8 → 9) Первый элемент равен 1, поэтому можно перейти только к 3. Второй элемент равен 3, поэтому можно сделать не более 3 шагов, то есть до 5 или 8 или 9.

Источник: http://www.geeksforgeeks.org/minimum-number-of-jumps-to-reach-end-of-a-given-array/

Я сделал линейный алгоритм времени для нахождения минимального количества прыжков, необходимых для достижения конца массива.

Исходный код выглядит следующим образом:

int minJumpsUpdated(int arr[], int n)
{
  int *jumps = malloc(n * sizeof(int));  // jumps[n-1] will hold the result
  int i =1, j = 0;

  jumps[0] = 0;
  for (i = 1; i < n; ) { 

    // if i is out of range of arr[j], then increment j
    if (arr[j] + j < i && j < i) {

      j++;

    // else if i is within range of arr[j], 
    //   jumps for ith element would be jumps[j]+1
    } else if (arr[j] + j >= i && j < i) {

      jumps[i] = jumps[j] + 1;
      i++;

    } else {
      printf("solution does not exist");
      return -1;
    }
  }

  printf("jumps: ");
  for (i = 0; i < n; i++) {
    printf("%d, ", jumps[i]);
  }
  return jumps[n - 1];
}

Пример:

1.) изначально i=1, j=0 и arr[] = {1, 3, 6, 1, 0, 9};

jumps[] = 0,0,0,0,0,0

2.), поскольку i находится в диапазоне от arr[j] т.е. i<= j+arr[j], количество прыжков, необходимых для перехода в i-ю позицию, будет минимальным числом прыжков до j-й позиции + 1.

i=2, j=0, jumps[] = 0,1,0,0,0,0

3.) i>j+arr[j] т.е. j++;

i=2, j=1, jumps[] = 0,1,0,0,0,0

4.) i<=j+arr[j] т.е. jumps[i] = jumps[j]+1;

i=3, j=1, jumps[] = 0,1,2,0,0,0

5.) i<=j+arr[j] т.е. jumps[i] = jumps[j]+1;

i=4, j=1, jumps[] = 0,1,2,2,0,0

6.) i<=j+arr[j] т.е. jumps[i] = jumps[j]+1;

i=5, j=1, jumps[] = 0,1,2,2,2,0

7.) i>j+arr[j] т.е. j++;

i=5, j=2, jumps[] = 0,1,2,2,2,0

8.) i<=j+arr[j] т.е. jumps[i] = jumps[j]+1;

i=6, j=2, jumps[] = 0,1,2,2,2,3

------ END ------

Я не могу понять, в какой тестовой ситуации эта программа не будет работать. Я спрашиваю об этом, потому что в Интернете оптимизированное решение использует DP, который является O (n ^ 2). Мое решение - это линейное время. то есть O (n). Поэтому я предполагаю, что есть некоторые случаи, которые этот алгоритм не будет обрабатывать. Поэтому мне любопытно, в каких случаях он не справляется.

Ваша помощь будет оценена.

Спасибо.

Ответ 1

Резюме вашего алгоритма:

  • Возьмите первый элемент и посмотрите, как далеко вы можете добраться с этим
    (приращение i до arr[j]+j < i)
  • Перейдите к следующему элементу, который вы можете получить от первого, и который перенесет вас по крайней мере в i -й элемент.
  • Повторяйте это, пока не дойдете до последней записи.

Во-первых:
Да, он работает в O(n), так как алгоритм подталкивает как i a j только один раз от 1 до n в худшем случае.

Второй
Я не видел доказательства того, что O(n²) является оптимальной временной сложностью.

Thrid
Вы можете визуализировать arr следующим образом: ArrayJumpVisualization поэтому это именно то, что делает ваш алгоритм. Вы можете использовать это для доказательства по индукции, что ваш алгоритм правильный. Но, как сказал @Leo, должно быть решение.

Исправление для случая без решения
Убедитесь, что j < i имеет значение.

Ответ 2

Я думаю, что ваш код верен, если есть решение, что, если нет решения, например, что, если вход [0, 2, 3, 4]?

Кроме того, я думаю, что ваш алгоритм верен, вот мое решение, когда я решил эту проблему, ему нужно только постоянное пространство и все еще линейное время. В основном для каждого шага вы переходите к позиции, которая может перейти на большинство шагов на следующем шаге.

int jump(int A[], int n) {
    int jumps = 0;
    if(n < 2){
        return jumps;
    }
    int cur = 0; // current index,
    int cur_step;// number of step you can jump in current index 
    int last;    // last index
    int temp_max = cur; // temporary max jump distance 
    int temp_index = cur;// temporary index.

    while(cur < n){
        last = cur;
        cur_step = A[cur];
        if((cur + cur_step) >= n-1){ // if reached end of the array, return.
            jumps++;
            return jumps;
        }
        for(int ii = cur + 1; ii <= cur + cur_step; ii++){//go thru all the possible next position, and find the one that could jump most steps.
            if(A[ii] == 0){
                continue;
            }
            if(A[ii] + ii > temp_max){ // find the one that could jump most steps.
                temp_index = ii;
                temp_max = A[ii] + ii;
            }
        }
        cur = temp_index; // jump to this position, temp index holds index that jump most steps in next jump.
        if(cur != last){
            jumps++;
        }else{
            break;
        }
    }
    return -1;


}
};

Ответ 3

Спасибо за задание вопроса и предоставление кода. Это очень простой и спускный подход:). Я использовал тот же подход, и он прошел все тестовые примеры на одной из платформ кодирования. Предоставляя ниже небольшой код, написанный в java, который удовлетворяет всем тестовым случаям...

public int jump(ArrayList<Integer> a) {

    int dp[]=new int[a.size()];
    if(a.size()==1  || a.size() == 0)
        return 0;
    if(a.get(0)==0)
        return -1;
    Arrays.fill(dp,Integer.MAX_VALUE);      
    dp[0]=0;
    int j=0;
    for(int i=1;i<a.size() && j<a.size();)
    {
        if(j+a.get(j)>=i && dp[j]!=Integer.MAX_VALUE)
            {
                dp[i]=Math.min(dp[j]+1,dp[i]);
                i++;
            }
       else
            j++;
    }
    if(dp[a.size()-1]==Integer.MAX_VALUE)
        return -1;
   return dp[a.size()-1];     
}