递归求和带有规则的数字 – 仅使用递归

huangapple go评论135阅读模式
英文:

Recursion sum numbers *with rule* - Recursion only

问题

以下是翻译好的部分:

这个练习是:

仅使用递归(无循环)

查找数组中是否存在子序列的数字之和等于给定数字,并遵循以下规则。

假设我有这个数组,我为函数提供一个数字作为和,它必须遵循这个规则:
您不能重复使用相同的数字,也不能连续求和3个数字(不能做 i+1 和 i+2)

int[] a = {5,4,2,1,3};

所以在这个情况下:
数字 8 = true(4+3+1),(5+3)
数字 11 = false(4+5+2 是3个连续的,但是连续三个),(5+2+1+3 也是连续三个)

我的尝试是:

public static boolean sumRule(int[] a , int num){
    if (num == 0){
        return true;
    } else {
        return sumRule(a,num,0,a.length);
    }
}

private static boolean sumRule(int[] a, int num, int low,int high){
    if(low >= high || low < 0){
        return false;
    }

    if (a[low] == -1){
        return false;
    }

    if(a[low] == num || num-a[low] == 0 ){
        return true;
    }

    int temp = a[low];
    a[low] = -1;

    return  sumRule(a,num,low,high) || sumRule(a,num-temp,low+3,high) || sumRule(a,num-temp,low+1,high) ;

}

但是当我将 11 传递给这个函数时,它仍然返回 true,有人知道我在这里漏掉了什么吗?

谢谢,

英文:

So the exercise is:

Using recursion only (no loops)

Find if there is sub ground of numbers that are equal to the given number in an array and follow the rule.

Let's say I have this array, I give the function a number for sum and it must adhere to this rule:
you cannot repeat the same number, and you can't sum 3 numbers in a row (can't do i+1 and i+2)

int[] a = {5,4,2,1,3};

So in this case:
num 8 = true (4+3+1) ( 5+3)
num 11 = false (4+5+2 are 3 but are three in a row) (5+2+1+3 also three in a row)

My attempt is:

public static boolean sumRule(int[] a , int num){
        if (num == 0){
            return true;
        } else {

    return sumRule(a,num,0,a.length);
        }
}

private static boolean sumRule(int[] a, int num, int low,int high){
    if(low &gt;= high || low &lt; 0){
        return false;
    }

    if (a[low] == -1){
        return false;
    }

    if(a[low] == num || num-a[low] == 0 ){
        return true;
    }

    int temp = a[low];
    a[low] = -1;

    return  sumRule(a,num,low,high) || sumRule(a,num-temp,low+3,high) || sumRule(a,num-temp,low+1,high) ;
    
}

But when I send 11 to this, it still returns true, anyone has an idea what am i missing here?

Thanks,

答案1

得分: 2

下面是完整的代码答案,以及解释:

基本思路是将问题分解为递归。在每一步中,你需要考虑选择(即是否在求和中使用一个数字),然后递归计算两种选项。

基本情况:
如果 num == 0,则为真。但是如果 num != 0 且数组长度为 0,则为假。

递归情况:
我们检查数组中的第一个数字是否小于等于 num。如果不是,则不能使用它。因此,我们对所有相同的参数进行递归调用,除了数组现在是原始数组减去第一个数字。

如果我们可以使用数字(即 a[0] <= num),则真实的答案可能使用它,也可能不使用它。我们为每种情况进行递归调用,如果递归调用中的任何一个返回真,则返回真。

连续数字规则:
这很容易实现。我们添加一个名为“left”的参数,它告诉我们连续从数组开头可以取出的元素数量。一开始,left 为 2,因为最多可以连续取 2 个数字。然后在我们使用数组中的第一个数字的情况下,我们将 left 减少。如果我们不使用数组中的第一个数字,我们将 left 重置为 2。当 left 变为 0 时,我们别无选择,只能跳过数组顶部的当前数字。

以下是提供的代码的翻译部分:

class Main {
  public static void main(String[] args) {
    int[] a = new int[] {5,4,2,1,3};
    System.out.println(sumRule(a, 8));
    System.out.println(sumRule(a, 11));
  }

  public static boolean sumRule(int[] a , int num){
    if (num == 0){
        return true;
    } else {
      return sumRule(a,num,2);
    }
  }

  private static boolean sumRule(int[] a, int num, int left){
      if (num == 0) {
        return true;
      }

      if (a.length == 0) {
        return false;
      }
      
      int[] a_new = new int[a.length-1];
      for (int i = 1; i < a.length; i++) a_new[i-1] = a[i];

      if (left == 0) {
        return sumRule(a_new, num, 2);
      }

      boolean using_a0 = false;
      if (a[0] <= num) {
        using_a0 = sumRule(a_new, num-a[0], left-1);
      }

      boolean not_using_a0 = sumRule(a_new, num, 2);

      return (not_using_a0 || using_a0);
  }
}

编辑 - 在不复制数组的变体上:

class Main {
  public static void main(String[] args) {
    int[] a = new int[] {5,4,2,1,3};
    System.out.println(sumRule(a, 8));
    System.out.println(sumRule(a, 11));
  }

  public static boolean sumRule(int[] a , int num){
    if (num == 0){
        return true;
    } else {
      return sumRuleNoLoop(a,num,2,0);
    }
  }

  private static boolean sumRuleNoLoop(int[] a, int num, int left, int startIdx){
      if (num == 0) {
        return true;
      }

      if (startIdx >= a.length) {
        return false;
      }

      if (left == 0) {
        return sumRuleNoLoop(a, num, 2, startIdx+1);
      }

      boolean using_a0 = false;
      if (a[startIdx] <= num) {
        using_a0 = sumRuleNoLoop(a, num-a[startIdx], left-1, startIdx+1);
      }

      boolean not_using_a0 = sumRuleNoLoop(a, num, 2, startIdx+1);

      return (not_using_a0 || using_a0);
  }
}
英文:

I have the full code answer below, and here's the explanation:

Essentially you need to break this problem down to a recurrence. What that means is, you look at the choice at each step (i.e. whether to use a number or not in the sum) and recursively calculate both options.

The base case:
If num == 0 then we know it's true. But if num != 0 and the array has length 0, then we know it's false

Recursive case:
We check if the first number in the array is less than or equal to num. If not, then we can't use it. So we do a recursive call with all the same parameters except the array is now the original array minus the first number

If we CAN use the number (i.e. a[0] &lt;= num) then the true answer might use this or it may not use it. We make a recursive call for each case, and return true if either of the recursive calls return true.

The consecutive number rule:
This is easy to enforce. We add a parameter called 'left' which tells us the number of elements we can consecutively take from the beginning of the array. To start with, left is 2 because at most we can take 2 consecutive numbers. Then in the cases where we DO use the first number in the array in our sum, we decrement left. If we don't use the first number in the array, we reset left to 2. In the cases where left becomes 0, we have no choice but to skip the current number at the top of the array.

class Main {
public static void main(String[] args) {
int[] a = new int[] {5,4,2,1,3};
System.out.println(sumRule(a, 8));
System.out.println(sumRule(a, 11));
}
public static boolean sumRule(int[] a , int num){
if (num == 0){
return true;
} else {
return sumRule(a,num,2);
}
}
private static boolean sumRule(int[] a, int num, int left){
if (num == 0) {
return true;
}
if (a.length == 0) {
return false;
}
int[] a_new = new int[a.length-1];
for (int i = 1; i &lt; a.length; i++) a_new[i-1] = a[i];
if (left == 0) {
return sumRule(a_new, num, 2);
}
boolean using_a0 = false;
if (a[0] &lt;= num) {
using_a0 = sumRule(a_new, num-a[0], left-1);
}
boolean not_using_a0 = sumRule(a_new, num, 2);
return (not_using_a0 || using_a0);
}
}

Edit - A variation on the code above without copying the array:

class Main {
public static void main(String[] args) {
int[] a = new int[] {5,4,2,1,3};
System.out.println(sumRule(a, 8));
System.out.println(sumRule(a, 11));
}
public static boolean sumRule(int[] a , int num){
if (num == 0){
return true;
} else {
return sumRuleNoLoop(a,num,2,0);
}
}
private static boolean sumRuleNoLoop(int[] a, int num, int left, int startIdx){
if (num == 0) {
return true;
}
if (startIdx &gt;= a.length) {
return false;
}
if (left == 0) {
return sumRuleNoLoop(a, num, 2, startIdx+1);
}
boolean using_a0 = false;
if (a[startIdx] &lt;= num) {
using_a0 = sumRuleNoLoop(a, num-a[startIdx], left-1, startIdx+1);
}
boolean not_using_a0 = sumRuleNoLoop(a, num, 2, startIdx+1);
return (not_using_a0 || using_a0);
}
}

答案2

得分: 1

首先,您可以添加一个检查,以确保不要连续添加3个数字。此外,将数组中的一个数字替换为“-1”将会在递归调用中产生意想不到的副作用。以下是您提供的代码内容:

解释:
递归的 sumRule 方法将问题分成两部分:

  • 第一部分将当前索引处的值与从下一个索引开始的值的和相加。
  • 第二部分假设无法使用当前值进行求和。它仅检查是否存在从数组的下一个值开始的子集之和。

在该方法中,lastIndex 用于跟踪选取的最后一个值的索引。因此,在第一次调用中,该值为0,在第二次调用中为1,依此类推。

(start - lastIndex <= 1 ? consecutive + 1 : 1) 用于检查是否应增加 consecutive 的值。consecutive = 1 表示当前值已添加到求和中。

以下是翻译后的代码:

public static boolean sumRule(int[] a, int num) {
    if (num == 0) {
        return true;
    } else {
        return sumRule(a, num, 0, 0, 0, 0, "");
    }
}

public static boolean sumRule(final int[] a, int num, int sum, int start, int consecutive, int lastIndex,
                              String index) {
    if (consecutive == 3) {
        return false;
    }

    if (sum == num) {
        System.out.println(index);
        return true;
    }

    if (start >= a.length) {
        return false;
    }

    return sumRule(a, num, sum + a[start], start + 1, (start - lastIndex <= 1 ? consecutive + 1 : 1), start,
                   index + ", " + start) || sumRule(a, num, sum, start + 1, consecutive, lastIndex, index);
}

如果您有任何进一步的问题或需要其他帮助,请随时问我。

英文:

First thing you can add is a check to see not 3 numbers in a row being added. Also replacing a number in the array with -1 would have unintended side effects within recursive calls. Below is something I have. You can ignore the index param I have used to see the values used.

Explanation:
The recursive sumRule method divides the problem into two parts:

  • First part takes the value of current index and adds with the sum of values starting from next index.
  • Second part assumes, current value can’t be taken for the sum. It only checks if there is a sum within the subset starting from next value of the array.

In the method, lastIndex is keeping track of the index of last value picked up for the sum. So, in the first call the value is 0, 1 in second and so on.

(start - lastIndex &lt;= 1 ? consecutive + 1 : 1) is to check whether value of consecutive should be increased or not. consecutive = 1 means, current value is added to the sum.

  public static boolean sumRule(int[] a, int num) {
if (num == 0) {
return true;
} else {
return sumRule(a, num, 0, 0, 0, 0, &quot;&quot;);
}
}
public static boolean sumRule(final int[] a, int num, int sum, int start, int consecutive, int lastIndex,
String index) {
if (consecutive == 3) {
return false;
}
if (sum == num) {
System.out.println(index);
return true;
}
if (start &gt;= a.length) {
return false;
}
return sumRule(a, num, sum + a[start], start + 1, (start - lastIndex &lt;= 1 ? consecutive + 1 : 1), start,
index + &quot;, &quot; + start) || sumRule(a, num, sum, start + 1, consecutive, lastIndex, index);
}

答案3

得分: 1

以下是我的实现。它包含了解释不同部分功能的注释。

public class RecurSum {
    /**
     * 确定 'sum' 是否等于 'target'。
     * 
     * @param arr         - 对其元素求和
     * @param sum         - 'arr' 中某些元素的和
     * @param target      - 所需的 'sum' 值
     * @param index       - 'arr' 中的索引
     * @param consecutive - 连续索引的数量,用于确保不超过 3 个
     * @param start       - 用于回溯的 'arr' 中的起始元素
     * 
     * @return "true" 如果 'sum' 等于 'target'
     */
    private static boolean sumRule(int[] arr, int sum, int target, int index, int consecutive, int start) {
        if (sum == target) {
            return true;
        } else {
            if (index >= arr.length) {
                // 如果已到达 'arr' 的最后一个元素,则回溯并重新开始
                if (start < arr.length) {
                    return sumRule(arr, 0, target, start + 1, 0, start + 1);
                }
                // 已到达 'arr' 的最后一个元素且无法回溯
                return false;
            } else {
                consecutive++;
                if (consecutive == 3) {
                    // 跳过第三个连续元素(根据规则)
                    consecutive = 0;
                    return sumRule(arr, sum, target, index + 2, consecutive, start);
                } else {
                    if (sum + arr[index] > target) {
                        // 递归调用,但不添加当前 'arr' 元素
                        return sumRule(arr, sum, target, index + 1, 0, start);
                    }
                    // 递归调用:将当前 'arr' 元素添加到 'sum' 中,并继续下一个元素
                    return sumRule(arr, sum + arr[index], target, index + 1, consecutive, start);
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = new int[]{5, 4, 2, 1, 3};

        // 初始调用递归方法,目标为 11
        System.out.println(sumRule(arr, 0, 11, 0, 0, 0));

        // 初始调用递归方法,目标为 8
        System.out.println(sumRule(arr, 0, 8, 0, 0, 0));
    }
}
英文:

Here is my implementation. It contains comments explaining what the different parts do.

public class RecurSum {
    /**
     * Determines whether &#39;sum&#39; equals &#39;target&#39;.
     * 
     * @param arr         - its elements are summed
     * @param sum         - sum of some elements in &#39;arr&#39;
     * @param target      - required value of &#39;sum&#39;
     * @param index       - index in &#39;arr&#39;
     * @param consecutive - number of consecutive indexes summed to ensure don&#39;t exceed 3
     * @param start       - starting element in &#39;arr&#39; which is used for back-tracking
     * 
     * @return &quot;true&quot; if &#39;sum&#39; equals &#39;target&#39;
     */
    private static boolean sumRule(int[] arr, int sum, int target, int index, int consecutive, int start) {
        if (sum == target) {
            return true;
        }
        else {
            if (index &gt;= arr.length) {
                // if we have reached last element in &#39;arr&#39; then back-track and start again
                if (start &lt; arr.length) {
                    return sumRule(arr, 0, target, start + 1, 0, start + 1);
                }
                // we have reached last element in &#39;arr&#39; and cannot back-track
                return false;
            }
            else {
                consecutive++;
                if (consecutive == 3) {
                    // skip 3rd consecutive element (because of the rule)
                    consecutive = 0;
                    return sumRule(arr, sum, target, index + 2, consecutive, start);
                }
                else {
                    if (sum + arr[index] &gt; target) {
                        // recursive call but don&#39;t add current element of &#39;arr&#39;
                        return sumRule(arr, sum, target, index + 1, 0, start);
                    }
                    // recursive call: add current element of &#39;arr&#39; to &#39;sum&#39; and proceed to next element
                    return sumRule(arr, sum + arr[index], target, index + 1, consecutive, start);
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = new int[]{5, 4, 2, 1, 3};

        // initial call to recursive method with target = 11 (eleven)
        System.out.println(sumRule(arr, 0, 11, 0, 0, 0));

        // initial call to recursive method with target = 8
        System.out.println(sumRule(arr, 0, 8, 0, 0, 0));
    }
}

答案4

得分: 0

public static boolean isSum(int[] a, int index, int sum){

    if(sum==0){
        return true;
    }

    if(index>=a.length-1 || sum<0){
        return false;
    }

    return isSum(a,index+3,sum-a[index]-a[index+1]) || isSum(a,index+2,sum-a[index]) || isSum(a,index+1,sum);
}


public static boolean isSum(int[] a, int sum){

    return isSum(a,0,sum);

}
英文:
public static boolean isSum(int[] a, int index, int sum){
if(sum==0){
return true;
}
if(index&gt;=a.length-1 || sum&lt;0){
return false;
}
return isSum(a,index+3,sum-a[index]-a[index+1]) || isSum(a,index+2,sum-a[index]) || isSum(a,index+1,sum);
}
public static boolean isSum(int[] a, int sum){
return isSum(a,0,sum);
}

huangapple
  • 本文由 发表于 2020年5月30日 07:12:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/62095869.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定