如何查找数组中包含相等总和的子集。 例如
{1,2,3,4,2}->{1,2,3} && {4,2}
{1,1,3,3,2,8}->{1,3,3,2}&&{1,8}
{1,3,4,7}->no subset
我尝试使用下面的代码,但没有得到适当的输出。
import java.util.*
public static void main(String[] args) {
int arr[] = {1,3,4,7};
int sum = getSum(arr, arr.length);
int[] solution = new int[arr.length];
find(arr, 0, 0, sum, solution);
}
public static int getSum(int arr[], int n) {
float sum = 0f;
for (int i = 0; i < n; i++)
sum = sum + arr[i];
return Math.round(sum / 2);
}
public static void find(int[] A, int currSum, int index, int sum,
int[] solution) {
if (currSum == sum) {
System.out.println("\nSum found");
for (int i = 0; i < solution.length; i++) {
if (solution[i] == 1) {
System.out.print(" " + A[i]);
}
}
} else if (index == A.length) {
return;
} else {
solution[index] = 1;// select the element
currSum += A[index];
find(A, currSum, index + 1, sum, solution);
currSum -= A[index];
solution[index] = 0;// do not select the element
find(A, currSum, index + 1, sum, solution);
}
return;
}
使用此输入数组:1,2,3,4,2低于输出
1 2 3
1 3 2
2 4
4 2
输入数组:1、1、3、3、2、8
1 3 3 2
1 8
1 3 3 2
1 8
输入数组:1、3、4、7
1 3 4
1 7
答案 0 :(得分:0)
要解决此问题,您的代码中至少需要3个嵌套循环 sudocode就像
for (i=0,i< array.length-1,i++){
for(k=i;k<array.length-1,k++){
fsum=findSum(i/*from*/,k/*to*/,array);
ssum=0;
for(x=k,x<array.length,x++){
secondsum=findSum(k,x,array);
if(fsum==ssum){
prend(i,k,array);
print(k,x,array);
break;
}
}
}
}
请注意,这只是需要实现的sudo代码
答案 1 :(得分:0)
代码的重复部分工作正常。在相当外围的部分中只有两个小缺陷:
这两个子集仅在数字之和为偶数时存在。您的代码未考虑此要求,这是有关{1,3,4,7}失败的原因。为此,对main函数的主体进行了一些修改,以便仅对偶数和执行重复操作。
您应该对重复项进行分类,以防止重复与{1,2,3,4,2}和{1,1,3,3,2,8}有关。为此,必须非常简单地存储结果子集。然后,在消除重复项之后,将剩下的子集打印出来。为了方便起见,这两种功能都封装在添加的SubsetPair类中,该类提供了storeSubsetPair和printSubsetPairList方法分别用于存储和打印。
修改后的代码为:
import java.util.*;
public class Main {
public static void main(String[] args) {
int arr[] = {1,3,4,7};
int sum = getSum(arr, arr.length);
int[] solution = new int[arr.length];
// find(arr, 0, 0, sum, solution); // REPLACED WITH: -----------------
if (sum % 2 == 0) {
sum = Math.round(sum / 2f);
find(arr, 0, 0,sum, solution);
}
SubsetPair.printSubsetPairList();
// -------------------------------------------------------------------
}
public static int getSum(int arr[], int n) {
// float sum = 0f; // REPLACED WITH: ---------------------------------
int sum = 0;
// -------------------------------------------------------------------
for (int i = 0; i < n; i++)
sum = sum + arr[i];
// return Math.round(sum / 2); // REPLACED WITH: ---------------------
return sum;
// -------------------------------------------------------------------
}
public static void find(int[] A, int currSum, int index, int sum,
int[] solution) {
if (currSum == sum) {
// System.out.println("\nSum found"); // REPLACED WITH: ----------
// for (int i = 0; i < solution.length; i++) {
// if (solution[i] == 1) {
// System.out.print(" " + A[i]);
// }
// }
SubsetPair.storeSubsetPair(A, solution);
// ---------------------------------------------------------------
} else if (index == A.length) {
return;
} else {
solution[index] = 1;// select the element
currSum += A[index];
find(A, currSum, index + 1, sum, solution);
currSum -= A[index];
solution[index] = 0;// do not select the element
find(A, currSum, index + 1, sum, solution);
}
return;
}
}
//NEW: Class for storage and print:
class SubsetPair {
private static List<SubsetPair> subsetPairList = new ArrayList<>();
private List<Integer> subset1 = new ArrayList<>();
private List<Integer> subset2 = new ArrayList<>();
//
// Storage of the subset pair
//
public static void storeSubsetPair(int[] A, int[] solution) {
SubsetPair subsetPair = new SubsetPair();
for (int i = 0; i < solution.length; i++) {
if (solution[i] == 1) {
subsetPair.subset1.add(A[i]);
} else {
subsetPair.subset2.add(A[i]);
}
}
if (!subsetPair.isDuplicate()) {
subsetPairList.add(subsetPair);
}
}
// Remove duplicates
private boolean isDuplicate() {
for (SubsetPair subsetPair : subsetPairList) {
if (isEqual(subset1, subsetPair.subset2) && isEqual(subset2, subsetPair.subset1) ||
isEqual(subset1, subsetPair.subset1) && isEqual(subset2, subsetPair.subset2)) {
return true;
}
}
return false;
}
private boolean isEqual(List<Integer> subset1, List<Integer> subset2) {
return subset1.containsAll(subset2) && subset2.containsAll(subset1);
}
//
// Output of the subset pairs
//
public static void printSubsetPairList() {
if (subsetPairList.size() == 0) {
System.out.println("No subset-pairs found!");
} else {
for (int i = 0; i < subsetPairList.size(); i++) {
subsetPairList.get(i).printSubsetPair(i + 1);
}
}
}
private void printSubsetPair(int i) {
System.out.print(i + ". Subset-Pair:\n");
System.out.print("Subset 1: ");
for (Integer i1 : subset1) {
System.out.print(i1 + " ");
}
System.out.println();
System.out.print("Subset 2: ");
for (Integer i2 : subset2) {
System.out.print(i2 + " ");
}
System.out.print("\n\n");
}
}
进行这些更改后,输出将变为:
对于{1,2,3,4,2},且总和为12:
1. Subset-Pair:
Subset 1: 1 2 3
Subset 2: 4 2
对于{1,1,3,3,2,8}(偶数为18):
1. Subset-Pair:
Subset 1: 1 3 3 2
Subset 2: 1 8
对于{1,3,4,7},赔率为15:
No subset-pairs found!
对于{3,1,1,2,2,1},且总和为10:
1. Subset-Pair:
Subset 1: 3 1 1
Subset 2: 2 2 1
2. Subset-Pair:
Subset 1: 3 2
Subset 2: 1 1 2 1
对于{2,4,8},且总和为14:
No subset-pairs found!
正如已经在评论中指出的那样,问题与“分区问题”有关,这是决定是否可以将正整数的多集划分为相等总和的两个子集的任务。例如,这被详细解释。在 https://en.wikipedia.org/wiki/Partition_problem或https://www.geeksforgeeks.org/partition-problem-dp-18/中(后者包括Java实现)。但是这两个问题不完全相同,因为“分区问题”的解决方案只是回答了问题如果可以将多集划分为两个子集,但不能明确确定子集本身。