法1:每次递归累加直至和为输入的数据
import java.util.Scanner;
public class Main {
//计数
static int count;
static int index = 0;//数组的索引
static int [] res = new int [30];//储存分解的子项,最多三十项
static int partNum;//部分和
static int n; //输入的数据
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
divsion(1);
}
static void divsion(int i) {
if (partNum == n) {
count++;
System.out.printf("%d=", n);
for (int k = 0; k < index - 1; k++) {
System.out.printf("%d+", res[k]);
}
if (count % 4 == 0 || res[index - 1] == n) {
System.out.printf("%d\n", res[index - 1]);
} else {
System.out.printf("%d;", res[index - 1]);
}
}
else if (partNum > n) { //累加和大于n,直接跳出
return;
} else {
for (int j = i; j <= n; j++) {
res[index++] = j;
partNum += j;
divsion(j);
partNum -= j;
index--;
}
}
}
}
最外层的循环为1~n,将每次循环分解得到的子项存储于res数组中,并让partNum加上该子项,当partNum的和等于n时,分解完成,可以输出记录的子项
缺点:会轮询很多不必要的情况,比如n=3,前两层递归已经1 1了,下一层递归循环1之后输出结果,然后会接着循环递归2和3这两种不必要的情况(正因此才会有elseif这种大于的情况)。
法2:每次递归累减直至差为0
import java.util.Scanner;
public class Main {
//计数
static int count;
static int [] res = new int [30];//储存分解的子项,最多三十项
static int n; //输入的数据
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
divsion(0, 1, n);
}
static void divsion(int index, int start, int num) {
if (num == 0) {
count++;
System.out.printf("%d=", n);
for (int k = 0; k < index - 1; k++) {
System.out.printf("%d+", res[k]);
}
if (count % 4 == 0 || res[index - 1] == n) {
System.out.printf("%d\n", res[index - 1]);
} else {
System.out.printf("%d;", res[index - 1]);
}
} else {
for (int i = start; i <= num; i++) {
res[index] = i;
start = i;
divsion(index + 1, start, num - i);
}
}
}
}
通过减法需要三个参数,index表示res数组中的索引,start表示分解的子项的最小值(开始点),为了保证子项从小到大输出,num表示还剩余的部分。
优点:不用循环很多不必要的情况,因为算法for循环主体的起始值是在变化的,会自动抛弃那些不必要的情况,比如n=3,第一层循环i=2时,下一层循环的start>=2,但是num-i=1,该情况就不会进行运算。
在网页版答题中,两种方法都不能满足n=30时的情况,会运算超时,可能是java代码运行慢的原因吧。
参考文章:https://blog.csdn.net/wulila/article/details/108088748
https://www.cnblogs.com/andywenzhi/p/5738715.html