我在创建一个递归方法以查找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);
}
}
}
}
答案 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);