【问题标题】:Recursion Question - Java - Minimum number of golf shots递归问题 - Java - 打高尔夫球的最少次数
【发布时间】:2019-10-13 05:09:03
【问题描述】:

我正在尝试根据给定的球杆长度计算我需要进行的最少击球次数。您也可以将其视为给定零钱所需的最少硬币数量。

我的代码是

   public static int golf(int holeLength, int[] clubLengths)
   {
   return golf(holeLength, clubLengths, 0);
   }

   public static int golf(int holeLength, int[] clubLengths, int shots)
   {
      if(holeLength==0) 
         shots+=0;
      else if(holeLength<0)
         shots=-1;
      else
      {      
         for(int i = 0; i<clubLengths.length; i++)
         {
            return golf(holeLength-clubLengths[i], clubLengths, shots+1);
         }
      }

      return shots;
   }

这里的问题是它似乎只根据数组上的第一个数字给出答案。因此,例如,如果我有 {25,50,100} 并且我想达到 100。显然,只需要最少一次,但程序只会使用 25 来计算它并说 4。同样,如果第一个数字是 21,那么它只会给出一个 stackoverflow。

【问题讨论】:

  • 它只检查第一个数字,因为 for 循环中的唯一指令是返回,因此在第一次迭代时它将返回并取消所有剩余的迭代。你需要重新考虑你的逻辑(我不太确定你想用这个数组实现什么)
  • 我的不好再读一遍就清楚了。您可以尝试在 for 循环中,或者从数组中的最大值开始,如果它是有序的,并检查它是否小于holelenght,或者可能不使用 return 并将结果放在一个临时变量中,并在循环中的每次迭代中尝试它并且只返回最小的镜头
  • 我试图不使用 return 而是使用 if 来比较每个镜头数量并且只存储最小的镜头,但它不会改变任何东西。所以我的新 for 循环是 for(int i = 0; i&lt;clubLengths.length; i++) { tempShots += 1+golf(holeLength-clubLengths[i], clubLengths, shots+1); if(tempShots&lt;=result) result=tempShots; }

标签: java arrays recursion


【解决方案1】:

以下是您的代码中发生的情况:当函数运行第一个循环时,它会获取clubLengths 中的第一个元素并立即返回而不进入下一个循环。你需要通过每一个可能的俱乐部来使用。

这是我的递归解决方案:

  1. 遍历每个俱乐部。
  2. 您可以选择使用当前俱乐部并再次使用它,
  3. 或者您可以选择使用当前俱乐部并使用下一个俱乐部,
  4. 或者您可以选择不使用当前俱乐部而使用下一个俱乐部。

我可以通过以下方式实现:

public static int golf(int holeLength, int[] clubLengths) {
    int[][] dp = int[clubLengths.length()][holeLength+1];
    return golf(holeLength, clubLengths, 0, dp);
}

private static int golf(int holeLength, int[] clubLengths, int ind, int[][] dp) {
    if (holeLength == 0) return 0;
    if (holeLength < 0) return -1;
    if (ind >= clubLengths.length()) return -1;
    if (dp[ind][holeLength] != 0) return dp[ind][holeLength];

    int rec1 = golf(holeLength-clubLengths[ind], clubLengths, ind, dp);
    if (rec1 == -1) rec1 = Integer.MAX_VALUE;
    else rec1++;

    int rec2 = golf(holeLength-clubLengths[ind], clubLengths, ind+1, dp);
    if (rec2 == -1) rec2 == Integer.MAX_VALUE;
    else rec2++;

    int rec3 = golf(holeLength, clubLengths, ind+1, dp);
    if (rec3 == -1) rec3 = Integer.MAX_VALUE;

    int result = Math.min(rec1, rec2);
    result = Math.min(result, rec3);
    if (result == Integer.MAX_VALUE) result = -1;

    dp[ind][holeLength] = result;
    return result;
}

除了递归之外,我还添加了 dp 以优化时间复杂度。因此,我的解决方案的时间复杂度将是 O(k*n),其中 k 是 holeLength,n 是 clubsLengths 中的元素数。如果您不想要 dp 并且只想要纯递归,则可以从上面删除所有 dp 的用法,代码仍然可以工作,但速度较慢。

【讨论】:

  • 这似乎工作得很好!谢谢,但是,对于我的教授的要求,该解决方案看起来太先进了。有没有办法对我现有的代码进行一些更改以实现相同的目标?或许你能引导我找到答案?
  • @AbdullahShahid 试试这个: 1. 在 for 循环之前放入 int result = 0; 2. 在 for 循环中,不要返回递归结果,而是执行 result = Math.max(result, ~~recursive call~~)。 3. 在 for 循环之后,return result;。看看这是否能让你的代码工作。
  • 这给出了一个有趣的结果,所以现在不再依赖第一个球杆长度,而是依赖于最后一个球杆长度。哈哈,这个递归的东西真的对我造成了伤害,哈哈:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-25
  • 2018-09-22
  • 1970-01-01
  • 1970-01-01
  • 2011-08-01
  • 2022-11-12
相关资源
最近更新 更多