草庐IT

java - 从集合中找出其和为零的子集?

coder 2024-04-02 原文

我有一组这样的整数

{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);
    }
}

最佳答案

这是一个解决方案。

我首先解决第一个子问题:我假设所有数字和目标都是正数,然后我解决真正的问题。

为了实现这一点,我基本上将问题分解为子问题。

让我们用一个例子来说明:

数字: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 < target="">

关于java - 从集合中找出其和为零的子集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15532957/

有关java - 从集合中找出其和为零的子集?的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  6. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  7. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  8. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  9. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  10. java - Ruby 相当于 Java 的 Collections.unmodifiableList 和 Collections.unmodifiableMap - 2

    Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur

随机推荐