【问题标题】:Recursion algorithm for the sum of all elements in a list in javajava中列表中所有元素之和的递归算法
【发布时间】:2021-10-17 11:17:28
【问题描述】:

尝试进行递归练习,但我迷失了如何创建一种方法来获取列表中所有元素的总和。

这是我目前所拥有的:

    public int countNumberOfElements(int [] elements){
int count = elements.length;
    if (elements.length == 0) {
        return 0;
    }
    else {
        return (countNumberOfElements(elements) + elements[count-1]);
    }
}

【问题讨论】:

  • 您需要以递归方式传递位置(索引)和数组。并且喜欢return elements[pos] + sumOfElements(pos+1, elements) 表示当前索引值的总和与后来索引的子数组部分的总和
  • 我发布了一个错误的建议,因为该方法的名称确实很糟糕。它应该被称为sumElements 或类似的东西,而不是*count*NumberOfElements
  • @FedericoklezCulloca 哎呀我忘了重命名方法!我正在做另一个练习,并没有更改名称。谢谢提醒!
  • 请注意,ints 的总和可以产生需要long 的结果。

标签: java algorithm recursion


【解决方案1】:

您需要在方法中添加一个参数:index,以跟踪您在数组中的当前位置:

public int sumOfElements(int[] elements, int index) {
    if (index >= elements.length)
        return 0;
    return elements[index] + sumOfElements(elements, index + 1);
}

【讨论】:

  • 不知道你为什么被否决,这看起来是正确的。唯一的小问题是测试可能只是index == elements.length - 假设这将在内部调用(所以它不应该是公开的,但你正在关注那里的OP)所以@ 987654324@ 最多是@ 987654325@.
  • @RaffleBuffle 是的,这段代码也可以使用 ==,但我个人更喜欢 >= 以防有人解析的索引高于元素计数。
【解决方案2】:

你必须删除最后一个元素

public static int countNumberOfElements(int[] elements) {
    int count = elements.length;
    if (elements.length == 0) {
        return 0;
    } else {
        int newArray[] = Arrays.copyOf(elements, count - 1);
        return (countNumberOfElements(newArray) + elements[count - 1]);
    }
}

【讨论】:

    【解决方案3】:

    试试这样的。

     int getSum(int[] items){
        return getSum(items, items.length - 1, 0);
     }
    
     int getSum(int[] items, int index, int sum){
        return index < 0 ? sum: getSum(items, index - 1, sum + items[index]);
     }
    

    【讨论】:

      【解决方案4】:

      你可以试试:

      static int findSum(int A[], int N){
          if (N <= 0)
              return 0;
          return (findSum(A, N - 1) + A[N - 1]);
      }
      

      其中 A 是数组,N 是数组的长度。

      附:你在你的问题中提到了一个列表,然后在你的例子中使用和数组,所以我假设你的意思是数组?

      【讨论】:

        【解决方案5】:

        逐个元素地减少问题可能会导致即使是中等大小的数组也会出现堆栈溢出。这可以通过将范围值 firstlast 添加到递归方法的参数列表并将结果范围(大致)分成两半来生成两个长度相差不超过 1 的子范围来避免。递归地对每个子范围应用此拆分过程,直到您到达包含单个元素的范围,其“总和”是该元素的值。然后对递归调用的结果求和,并继续将累积结果传递回递归树。重复减半减少了对O(log(elements.length)) 而不是O(elements.length) 的递归调用次数。运行时间的递归是T(n) = 2T(n/2) + O(1) =&gt; O(n),所以这种方法(就像其他人提出的解决方案一样)以线性时间计算总和。

        我已经将实现分解为一个公共前端,它将数组作为其唯一参数,以及一个单独的私有递归,它具有范围信息的附加参数。这对最终用户隐藏了范围簿记。当递归需要可以从数据本身派生的信息,或者涉及只需要预先执行一次的值或类型检查时,这是一个常见且有用的技巧。将这些派生和检查分离到前端可以减少递归调用中完成的工作量,并使面向公众的方法界面更加用户友好。我还设置了返回类型long,因为两个ints 的总和会溢出int 的容量。以下代码:

        class Test {
        
            // Public facing front end
            public static long sumArray(int [] elements){
                int count = elements.length;
                if (count == 0) {
                    return 0L;
                } else {
                    return _sumArray_(elements, 0, count - 1);
                }
            }
        
            // Private recursive worker-bee to do the actual task.
            private static long _sumArray_(int [] elts, int first, int last) {
                // When focus is on a single element, return its value
                if (last == first) {
                    return (long) elts[first];
                }
                // Otherwise find the mid-range index for the current range
                int mid = first + (last - first) / 2;
                // Sum the sums of the two resulting sub-ranges
                return _sumArray_(elts, first, mid) + _sumArray_(elts, mid + 1, last);
            }
        
            public static void main(String[] args) {
                int [] ary = {5,6,7,1,2,3,4,8,9,10};
                System.out.println(sumArray(ary));
            }
        }
        

        main 中提供的测试数据生成正确答案 55。

        总而言之,这个解决方案:

        • 产生正确答案,即使数组包含非常大的int 值(返回long 以避免整数溢出);
          • 示例:使用返回 int 的方法处理 int [] ary = {2147483647,2147483647}; 将产生 -2 而不是 4294967294 的正确答案
        • 不需要最终用户记住和提供除数据本身之外的其他参数;
        • 与其他建议解决方案的时间复杂度相匹配;和
        • 在递归堆栈的大小上支配所有其他解决方案,因此如果将它用于包含数十万个或更多元素的数组,它不会导致堆栈溢出。
          • 示例:将大小为n 的问题划分为大小为1 和n-1 的子问题的方法将在int [] ary = new int[100000]; java.util.Arrays.fill(ary, 42); 等大型数组上生成java.lang.StackOverflowError,同时将问题分成连续的两半处理一个数组100M 个元素没有问题。

        【讨论】:

          【解决方案6】:

          您可以创建单独的递归方法并从您的方法中调用它:

          public int countNumberOfElements(int[] elements) {
              if (elements.length == 0)
                  return 0;
              else
                  return countNumberOfElementsRec(elements, 0);
          }
          
          public int countNumberOfElementsRec(int[] elements, int index) {
              if (index >= elements.length)
                  return 0;
              else
                  return elements[index] + countNumberOfElementsRec(elements, index + 1);
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-10-08
            • 2012-05-22
            • 1970-01-01
            • 2019-09-26
            • 2019-04-15
            • 1970-01-01
            • 2020-09-02
            相关资源
            最近更新 更多