从订阅博客中看到这道题,于是花了上午的时间写了一下,此题类似于0-1背包问题,故复习了一下,分别有递归和非递归的解法。
题目:给定一个数t,以及n个整数,在这n个整数中找到相加之和为t的所有组合,例如t = 4,n = 6,这6个数为[4, 3, 2, 2, 1, 1],这样输出就有4个不同的组合,它们的相加之和为4:4, 3+1, 2+2, and 2+1+1。请设计一个高效算法实现这个需求。
递归解法:
private static int[] a={4,3,2,2,2,1,1}; private static int t=8; private static int n=7; private static boolean[] flags;
public static int subNum(int s,int r){ if(s==0){ output(0); // System.out.println(r); return 1; }else{ if(s<0 || (s>0 && r>=n)){ return 0; }else{ flags[r]=true; int f=subNum(s-a[r],r+1); // while (r+1<n && a[r+1] == a[r]) // r++; flags[r]=false; f=subNum(s,r+1); return 0; /* * if(subNum(s-a[r],r+1)==1){ //System.out.println(s+" "+r); * return 1; }else{ flags[r]=false; return subNum(s,r+1); } */ } } } |
非递归算法:
private final static int N = 20; private static int W[] = { 1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 8, 8, 8, 10, // private static int W[]={4,3,2,2,2,1,1}; // 若原W无序,则先对其排序 private static int stack[] = new int[20]; private static int stackIdx; private static void output() { private static void outstack() { public static void subNum() { }
10, 10, 12, 12, 12 };
private final static int T = 20;
int i;
for (i = 0; i < stackIdx; i++) {
System.out.print(W[stack[i]] + " ");
}
System.out.println();
}
int i;
for (i = 0; i < stackIdx; i++) {
System.out.print(stack[i] + " ");
}
System.out.println();
}
int idx;
int sum;
idx = 0;
sum = T;
stackIdx = 0;
while (stackIdx >= 0) {
// System.out.println(" "+stackIdx+ " "+sum+" "+idx);
if (idx >= N) {
--stackIdx;
if (stackIdx < 0)
break;
sum += W[stack[stackIdx]];
idx = stack[stackIdx];
while (idx + 1 < N && W[idx + 1] == W[idx])
idx++;// 前后的元素相同,即可以跳过后面相同的元素,因为已经在前面一个元素遍历过
++idx;
} else {
sum -= W[idx];
stack[stackIdx++] = idx;
// System.out.println(" "+stackIdx+ " "+sum+" "+idx);
if (sum == 0) {
output();
--stackIdx;
sum += W[idx];
while (idx + 1 < N && W[idx + 1] == W[idx])
idx++;// 找到符合的条件,而下一次遍历的元素跟符合条件中的最后一个元素相同,即表明有重复相同的组合
++idx;
} else if (sum > 0) {
++idx;
} else {
--stackIdx;
if (stackIdx < 0)
break;
sum += W[idx];
idx = stack[stackIdx] + 1;
// while(idx+1<N && W[idx+1] == W[idx]&& flag)
// idx++;
}
}
}