我有一组像这样的整数
{1,4,5,2,7,8,-3,-5,-6,9,3,-7,-1,5,6}
该集合可以包含任意数量的项目,因为我需要从用户中获取输入所需的所有子集,其总和等于零,例如在上面的集合中,子集将是
{(1,2,-3)}
{(1,-1)}
{(3,-3)}
{(5,-5)}
等等
我已经尝试过这段代码但是当我将target
设置为零时,它并没有给我回答。
import java.util.ArrayList;
import java.util.Arrays;
class SumSet {
static void sum_up_recursive(ArrayList<Integer> numbers, int target,
ArrayList <Integer> partial)
{
int s=0;
for (int x: partial) s += x;
if (s == target)
System.out.println("sum("+Arrays.toString(partial.toArray())+")="+target);
if (s >= target)
return;
for(int i=0;i<numbers.size();i++) {
ArrayList<Integer> remaining = new ArrayList<Integer>();
int n = numbers.get(i);
for (int j=i+1; j<numbers.size();j++) remaining.add(numbers.get(j));
ArrayList<Integer> partial_rec = new ArrayList<Integer>(partial);
partial_rec.add(n);
sum_up_recursive(remaining,target,partial_rec);
}
}
static void sum_up(ArrayList<Integer> numbers, int target)
{
sum_up_recursive(numbers,target,new ArrayList<Integer>());
}
public static void main(String args[]) {
Integer[] numbers = {3,4,6,4,5,2,6};
int target = 9;
sum_up(new ArrayList<Integer>(Arrays.asList(numbers)),target);
}
}
答案 0 :(得分:2)
这是一个解决方案的提议。
我首先解决第一个子问题:我认为所有数字和目标都是正数,然后我解决了真正的问题。
为实现这一点,我基本上解决了子问题中的问题。
让我们用一个例子来说明:
数字:1,3,8,2,7目标:10
首先:对列表进行排序: 数字:8,7,3,2,1目标:10 然后递归地找到解决以下问题的方法:
数字:7,3,2,1目标:10-8 = 2
数字:3,2,1目标:10-7 = 3
数字:2,1目标:10-3 = 2
数字:1个目标:10-1 = 9
之前放置大数字的目的是快速消除包含此数字的解决方案(因为总和很快超过了目标)。
以下是解决此子问题的注释代码:
import java.util.ArrayList;
import java.util.List;
public class Problem {
/*
* Used at the end to recompose the solutions.
* This value is null for the root problem.
*/
private Integer nodeValue;
//The POSITIVE target sum
private int target;
//List of POSITIVE numbers, supposed to be sorted
private List<Integer> numbers;
private List<Problem> listSubProblems;
/*
* Link to the parent problem.
* Useful at the end to generate the results.
*/
private Problem parentProblem;
public Problem(int target, List<Integer> numbers, Integer nodeValue, Problem parentProblem){
this.target=target;
this.numbers=numbers;
this.nodeValue=nodeValue;
this.parentProblem=parentProblem;
this.listSubProblems =new ArrayList<Problem>();
}
public void solve(){
buildSubProblems();
for(Problem problem : listSubProblems){
problem.solve();
}
}
/**
* Builds a List of sub problems.
* For example, if {@link #numbers} contains 9 8 5 3, with target 10
* this method will return the following sub problems:
*
* <table>
* <tr>
* <td>nodeValue</td><td>target</td><td>numbers</td>
* </tr>
* <tr>
* <td>9</td><td>10-9=1</td><numbers>8 5 3</numbers>
* </tr>
* <tr>
* <td>8</td><td>10-8=2</td><numbers>5 3</numbers>
* </tr>
* <tr>
* <td>5</td><td>10-5=5</td><numbers>3</numbers>
* </tr>
*
* </table>
*
*/
private void buildSubProblems(){
int numbersSize=numbers.size();
/*
* Numbers are supposed to be positive so if the target is negative,
* there is no chance to find a valid solution.
* As the list of numbers is sorted, the case when target < 0 happens quickly
* Hence, it quickly removes combinations implying big numbers
*/
if(target>=0 && numbersSize> 1){
for(int i=0;i<numbersSize;i++){
Integer nodeValue=numbers.get(i);
List<Integer> subList=numbers.subList(i+1,numbersSize);
int newTarget=this.target-nodeValue;
Problem problem=new Problem(newTarget, subList, nodeValue, this);
System.out.println("Created problem: "+problem.dump());
this.listSubProblems.add(problem);
}
}
}
/**
* @return True is the Problem contains exactly one number and that number equals the target.
*/
public boolean isNodeSolution(){
return this.target==0;
}
public Integer getNodeValue(){
return this.nodeValue;
}
public List<Problem> getListSubProblems(){
return this.listSubProblems;
}
public Problem getParentProblem(){
return this.parentProblem;
}
public String dump(){
StringBuilder sb=new StringBuilder();
sb.append("{nodeValue: "+this.nodeValue);
sb.append("; target: "+target);
sb.append("; numbers:");
for(Integer integer : numbers){
sb.append(integer+",");
}
sb.append("}");
sb.append("Valid? : "+ isNodeSolution());
return sb.toString();
}
}
以下是显示如何测试它的代码:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception{
Integer numbers[]={1,3,8,2,7};
int target=10;
List<Integer> listNumbers= Arrays.asList(numbers);
Collections.sort(listNumbers);
Collections.reverse(listNumbers);
//Build the root problem
Problem problem=new Problem(target,listNumbers,null,null);
//Solve it
problem.solve();
//Dump the result.
dumpResult(problem);
System.out.println("Done!");
}
private static void dumpResult(Problem problem){
for(Problem p:problem.getListSubProblems()){
if(p.isNodeSolution()){
System.out.print("\nSolution :");
dumpSolution(p);
}
dumpResult(p);
}
}
private static void dumpSolution(Problem problem){
//If the current node is not the root problem
if(problem.getParentProblem()!=null){
System.out.print(problem.getNodeValue() + ", ");
dumpSolution(problem.getParentProblem());
}
}
}
以下是输出示例:
Created problem: {nodeValue: 8; target: 2; numbers:7,3,2,1,}Valid? : false
Created problem: {nodeValue: 7; target: 3; numbers:3,2,1,}Valid? : false
Created problem: {nodeValue: 3; target: 7; numbers:2,1,}Valid? : false
Created problem: {nodeValue: 2; target: 8; numbers:1,}Valid? : false
Created problem: {nodeValue: 1; target: 9; numbers:}Valid? : false
Created problem: {nodeValue: 7; target: -5; numbers:3,2,1,}Valid? : false
Created problem: {nodeValue: 3; target: -1; numbers:2,1,}Valid? : false
Created problem: {nodeValue: 2; target: 0; numbers:1,}Valid? : true
Created problem: {nodeValue: 1; target: 1; numbers:}Valid? : false
Created problem: {nodeValue: 3; target: 0; numbers:2,1,}Valid? : true
Created problem: {nodeValue: 2; target: 1; numbers:1,}Valid? : false
Created problem: {nodeValue: 1; target: 2; numbers:}Valid? : false
Created problem: {nodeValue: 2; target: -2; numbers:1,}Valid? : false
Created problem: {nodeValue: 1; target: -1; numbers:}Valid? : false
Created problem: {nodeValue: 2; target: 5; numbers:1,}Valid? : false
Created problem: {nodeValue: 1; target: 6; numbers:}Valid? : false
Solution :2, 8,
Solution :3, 7, Done!
现在,这并未涵盖隐含负数的初始问题。 要解决这种情况,请隔离所有负数并计算所有负数组合,并加上总和。
然后,对于负数的每个和,创建一个只包含正数和相应目标的子问题(初始目标 - 负数之和)
改善它的一种方法:问题的复杂性取决于负数组合的数量。因此,如果负数多于正数,则可以反转所有值并解决反转问题。
另一种改进方法:你可以在内存中保存每个子问题的正数之和。如果sum + nodeValue&lt;目标,继续探索分支是没用的。
答案 1 :(得分:1)
我在Google大学的采访中遇到了这个问题,并在很长的路上解决了这个问题。
考虑一下,如果一个集合为0,那么“有”为负数,并且“必须是一组正数”。
步骤:
1. Created a 2 arrays negativeNumArrays and POsitiveNumArrays
2. Create a new negative set(does not allows duplicate) which is possible sums of negative arrays ex -
[-1,-2,-3] = [-1,-2,-3, {-1-2=3},{-1,-3=-4},{-2,-3=-5},{-6}] = [-1,-2,-3,-4,-5,-6]
So the set looked like
Key:Value
"1" =-1
"2" = -2
...
"2:3"=-5
"1:2:3"=-6
Here
"N6" = -6
3. For this new set of negative array find combination in positive
array which matches any of the 6 negative arrays.
Same as above say positive numbers are 3 and 4
So the set would look like
"3"=3
"4"=4
"3:4"=7
Now simple compare the two sets and see which of these are equal
So for example Negative Set "1:3" = Positive Set "4"
and hence use Stringtokenizer to get the numbers from set key {-1,-3,4}
答案 2 :(得分:0)
您没有检查partial
是否为空,在sum_up_recursive()
== 0时,target
会在第一次尝试时立即返回。试试这个:
if (partial.size() > 0) {
for (int x : partial)
s += x;
if (s == target)
System.out.println("sum(" + Arrays.toString(partial.toArray()) + ")=" + target);
if (s >= target)
return;
}
注意,可能还有其他方法可以大大改进您正在使用的算法。我只是回答为什么你的代码没有按预期工作。