参考网上很多,玛德都不测试的吗?就贴出来了?浪费时间。互联网精神在哪!!!
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Scanner;
/**
* [编程题] 求和
* 输入两个整数 n 和 m,从数列1,2,3.......n 中随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来
* 输入描述:
* 每个测试输入包含2个整数,n和m
*
* 输出描述:
* 按每个组合的字典序排列输出,每行输出一种组合
*
* 输入例子1:
* 5 5
*
* 输出例子1:
* 1 4
* 2 3
* 5//注意这里是一个数的情况
*/
/**
* 分析:分治的思想。可以把问题(m,n)拆分(m - n, n -1)和(m, n - 1)。
* 1.首先判断,如果n>m,则n中大于m的数不可能参与组合,此时置n = m;
* 2.将最大数n加入且n == m,则满足条件,输出;
* 3.将n分两种情况求解,
* (1)n没有加入,取n = n - 1; m = m;递归下去;
* (2)n加入,取n = n - 1, m = m - n,递归下去
*/
public class ListAllPossibleCombinationsWhichSumIsM {
private static LinkedList<Integer> list = new LinkedList<>();
private static ArrayList<int[]> arrayList = new ArrayList<>();
public static void findSum(int n, int m) {
if (n < 1 || m < 1)
return;
if (m < n)
n = m;//这里实际上完成了 n = m-n 是从递归一开始累计的,不单单指这层
if (m == n) {
int[] temp = new int[list.size()+1];
temp[0] = m;//最小的先放进去
int index = 0;
for (int i = list.size()-1; i >= 0 ; i--){//倒着装进去 因为我们是从n开始的,也就是从大到小的递归,那么list中实际上是倒序
temp[++index] = list.get(i);
}
arrayList.add(temp);
}
list.addLast(n);
findSum(n - 1,m - n);//取了最后一个数,那么和m就减去最后一个数n m-n
list.removeLast();
findSum( n - 1,m);//最后一个数不可取 n没有加入,取n=n-1,m=m
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
findSum(n,m);
arrayList.sort(new Comparator<int[]>() {//字典序排序,先按照第一位,再按照第二位。。。
@Override
public int compare(int[] o1, int[] o2) {
if (o1[0] > o2[0]){
return 1;
}else if(o1[0] < o2[0]){
return -1;
}else {
if (o1[1] > o2[1]){
return 1;
}else if(o1[1] < o2[1]){
return -1;
}else{
return 0;
}
}
}
});
for (int[] ints : arrayList) {
for (int i = 0; i < ints.length; i++) {
System.out.print(ints[i]);
if (i != ints.length-1)
System.out.print(" ");
}
System.out.println();
}
}
}