Amicable数的递归方法,介于1 - 10000 Java之间

时间:2018-06-14 18:33:42

标签: java recursion

我在创建一个递归方法以查找1到10000之间的Amicable数时遇到问题。我创建了一个方法来查明两个数字是否是Amicable,但我不知道如何针对每个可能的数字组合运行它。以下是我写的两种方法。

public void amicable(int n, int m) {
    int sumM = 0;
    int sumN = 0;

    for (int i = 1; i < n; i++) {
        if (n % i == 0) {
            sumN += i;
        }
    }

    for (int j = 1; j < m; j++) {
        if (m % j == 0) {
            sumM += j;
        }
    }

    if (sumN == m && sumM == n) {
        System.out.println(n + " and " + m + " are amicable numbers");
    }
}

public static void amicableBetween(int n, int m) {
    int sumaM = 0;
    int sumaN = 0;
    if (m >= 1) {

        for (int j = 1; j < m; j++) {
            if (m % j == 0) {
                sumaM += j;
            }
        }

        for (int i = 1; i < n; i++) {
            if (n % i == 0) {
                sumaN += i;
            }
        }

        if (sumaN == m && sumaM == n) {
            System.out.println(n + " and " + m + " are amicable numbers");
            amicableBetween(n + 1, m - 1);
        } else {
            System.out.println(n + " i " + m + " aren't amicable numbers");
            amicableBetween(n + 1, m - 1);
        }
    }
}

}

4 个答案:

答案 0 :(得分:2)

轻微的免责声明,这种方法可能需要永远,你可能会耗尽堆栈空间,所以我不能100%确定从递归的1-10000计算所有友好数字是要走的路。如果这只是为了娱乐或练习,那我猜是好的。

一种方法是扫描n,直到我们到达m - 1并在每一步调用amicable(n,m)。在n达到m - 1后,我们可以将m减少1并重复此过程,直到n is equal to m - 1,然后我们检查了所有可能的组合。为此,您可以将两种方法分解为三种方法。

第一种方法是你已经拥有的amicable方法,只是更改了返回类型,以便我们可以在递归链的同时重用它:

public static boolean amicable(int n, int m) {
    int sumM = 0;
    int sumN = 0;

    for (int i = 1; i < n; i++) {
        if (n % i == 0) {
            sumN += i;
        }
    }

    for (int j = 1; j < m; j++) {
        if (m % j == 0) {
            sumM += j;
        }
    }

    return sumN == m && sumM == n;
}

第二种是public方法amicableBetween(int n, int m)

public static void amicableBetween(int n, int m) {

    amicableBetween(n, m, true);
}

将调用具有第三个参数private的第三个amicableBetween(int n, int m, boolean start)辅助方法start,该方法可用于识别n是否已达到m。然后,我们需要将m减少1并重复此过程:

private static void amicableBetween(int n, int m, boolean start) {

    if(n == m) {
        return;
    }

    if (m >= 1) {

        if (amicable(n, m)) {
            System.out.println(n + " and " + m + " are amicable numbers");
        } else {
            System.out.println(n + " and " + m + " aren't amicable numbers");
        }
        amicableBetween(n + 1, m, false);
    }
    if(start) {
        amicableBetween(n, m - 1, true);
    }
}

答案 1 :(得分:2)

我想知道您为什么要使用递归算法。你不担心 StackOvervlowException 吗?!在Map时间内使用简单O(n)很容易找到它:

public static void amicable(int lo, int hi) {
    Map<Integer, Integer> map = new HashMap<>();

    for (int i = lo; i <= hi; i++) {
        int j = map.computeIfAbsent(i, DIV_SUM);

        if (j > i && j <= hi && map.computeIfAbsent(j, DIV_SUM) == i)
            System.out.format("[%d : %d]\n", i, j);
    }
}

private static final Function<Integer, Integer> DIV_SUM = val -> {
    int sum = 0;

    for (int i = 1, max = val / 2; i <= max; i++)
        if (val % i == 0)
            sum += i;

    return sum;
};

演示:时间~150ms

amicable(1, 10000);

[220 : 284]
[1184 : 1210]
[2620 : 2924]
[5020 : 5564]
[6232 : 6368]

答案 2 :(得分:1)

所以,你写了一个方法,可以判断两个数字是否友好。这是困难的部分。你所要做的就是从两个循环中调用它,一个用于上限,一个用于下限。

for(lowerNumber = 1; lowerNumber < 10000; lowerNumber++){
    for(upperNumber = lowerNumber + 1; upperNumber <= 10000; upperNumber++){
        amicable(lowerNumber, upperNumber);
    }
}

答案 3 :(得分:0)

我不确定为什么在amicable函数中需要两个参数。友好数字具有句点2的重复等分序列,这意味着

s(s(n)) == n

我们可以通过检索其适当除数的总和并检查上面的断言来找到数字的补码。

这意味着要找到n在1到10,000之间的友好数字,我们只需要n,并且还会使您想要作为递归的过程中的部分变得微不足道。

JavaScript代码:

function s(n){
  let s = n > 1 ? 1 : 0;
  let sqrt_n = Math.sqrt(n);
  let d1=Math.floor(n/2);
  
  for (; d1>=sqrt_n; d1--){
    let d2 = n / d1;
    
    if (d2 == Math.floor(d2))
      s += d1 + d2;
  }
    
  if (d1 == sqrt_n)
    s += d1;
    
  return s;
}

let n = 220;
let s_n = s(n);

if (s(s_n) == n)
  console.log('Amicable!', n, s_n);