【问题标题】:Linear time algorithm for Minimum number of jumps required to reach end到达终点所需的最小跳跃次数的线性时间算法
【发布时间】:2014-06-11 15:42:14
【问题描述】:

问题:到达终点的最少跳跃次数

给定一个整数数组,其中每个元素表示可以从该元素向前执行的最大步数。编写一个函数来返回到达数组末尾(从第一个元素开始)的最小跳转次数。如果一个元素是 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=0arr[] = {1, 3, 6, 1, 0, 9};

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

2.) 因为iarr[j] 的范围内,即。 i&lt;= j+arr[j],到第 i 个位置所需的跳跃次数是到第 j 个位置的最少跳跃次数 + 1。

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

3.) i&gt;j+arr[j]j++;

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

4.) i&lt;=j+arr[j]jumps[i] = jumps[j]+1;

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

5.) i&lt;=j+arr[j]jumps[i] = jumps[j]+1;

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

6.) i&lt;=j+arr[j]jumps[i] = jumps[j]+1;

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

7.) i&gt;j+arr[j]j++;

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

8.) i&lt;=j+arr[j]jumps[i] = jumps[j]+1;

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

----- 结束 ------

我无法弄清楚该程序在哪个测试用例下不起作用。我问这个是因为在互联网上优化的解决方案使用的是 O(n^2) 的 DP。我的解决方案是线性时间。即 O(n)。因此,我假设该算法无法处理某些情况。所以我很好奇它不处理哪些情况。

您的帮助将不胜感激。

谢谢。

【问题讨论】:

  • @Jarod42 我试着改进了一下。
  • 嗯,我们只有你的程序,没有描述它应该做什么。如果该程序只是您的问题描述,那么是的,它总是可以正常工作。而且由于它总是线性的,如果有人证明了原始问题的下限,它显然无法正确描述问题。所以请给我们一个你应该解决的问题的明确定义。另外:您可以删除 C++ 标记,这是 C。然后,不要将 malloc 的返回值转换为 free 您的数组末尾。
  • @JensGustedt:我添加了问题陈述。此外,我将确保释放分配的内存。非常感谢您指出这一点。
  • @JensGustedt o(f) 表示上限,而不是下限。另外,为什么不只是提醒外星人,在问题中包含问题陈述本身(而不仅仅是指向它的链接)是很常见的?
  • 只要生成随机测试用例,比较两种算法的结果,如果存在反例,就可以找到。如果你没有找到,那不能证明你的算法是正确的,但如果你找到了,那就证明情况并非如此,只有这样,在我看来,把它带到 Stack Overflow 上才是明智的。顺便说一句,DP 方法可以通过范围最小查询在 O(n log n) 内实现。

标签: c algorithm data-structures dynamic-programming


【解决方案1】:

你的算法总结:

  1. 拿第一个项目,看看你能做到多远
    (递增 i 直到 arr[j]+j &lt; i
  2. 转到您可以从第一个项目到达的下一个项目,这至少会将您带到ith 项目。
  3. 重复此操作,直到到达最后一个条目。

第一:
是的,它在O(n) 中运行,因为在最坏的情况下,算法仅将ij1 推送到n 一次。

第二
我还没有看到证明O(n²) 是最佳时间复杂度。

第三
您可以像这样可视化arr 所以这正是你的算法所做的。您可以使用它通过归纳证明您的算法是正确的。但正如@Leo 所说,必须有一个解决方案。

修复无解决方案
确保 j &lt; i 成立。

【讨论】:

  • 酷可视化:)
  • 可视化让这里的算法看起来不是O(n),而是看起来像O(N^2)。想象一下输入 {9,8,7,6,5,4,3,2,1,0}。
  • 问题中的算法包含两个以线性时间运行的非嵌套循环。我真的不知道二次复杂度应该来自哪里。可视化没有显示复杂性。
【解决方案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];     
}

【讨论】:

  • 我试图把它藏在里面......没有发生......谢谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 1970-01-01
  • 2015-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多