简体   繁体   English

查找重复编号的所有组合以达到给定的总和

[英]Finding all combinations of duplicates numbers to reach a given sum

I want to finding all combinations in an array to reach a given sum. 我想在数组中找到所有组合以达到给定的总和。 For example if the array is [1,1,1,2,4,4] and the given target is 5 then should the output be: 例如,如果数组为[1,1,1,2,4,4]且给定目标为5,则输出应为:

Expected Output
1 1 1 2
1 4
1 4

This code is so far i did: 到目前为止,我已经执行了以下代码:

static void sum(int[] arr, int i, int sum, int target, String s) {
    for (int j = i + 1; j < arr.length; j++) {
        if (sum + arr[j] == target) {
            System.out.println(s + " " + String.valueOf(arr[j]));
        } else {
            sum(arr, j, sum + arr[j], target, s + " " + String.valueOf(arr[j]));
        }
    }
}

public static void main(String[] args) {
    int[] numbers = { 1, 1, 1, 2, 4, 4 };
    for (int i = 0; i < numbers.length; i++) {
        sum(numbers, i, numbers[i], 5, String.valueOf(numbers[i]));
    }

}

And the output of this code is : 此代码的输出为:

My Output
1 1 1 2
1 4
1 4
1 4
1 4
1 4
1 4

There is actually a problem when we have duplicates elements , its working for a non duplicates numbers, but not when there is duplicates numbers. 当我们有重复元素时,实际上存在一个问题,它适用于非重复数字,但是当存在重复数字时则没有。 I want to know how I can solve that problem so the output seems like the expected one. 我想知道如何解决该问题,因此输出看起来像预期的那样。

One of the basic objects we need to deal with in this problem is a Bag or MultiSet - an unordered set of values that can contain multiple instances of an element. 在这个问题中,我们需要处理的基本对象之一是Bag或MultiSet-一组可以包含元素的多个实例的无序值。 Unfortunately the Java Collections framework doesn't support this. 不幸的是,Java Collections框架不支持此功能。 Rather than mess around trying to get List to work we can write our own very basic version, with just the capabilities we need. 我们可以编写我们自己的非常基本的版本,而不仅仅是我们想要的功能,而不是为了使List正常工作而徒劳。 (The Guava library has a MultiSet, so you could look to that for production code). (Guava库具有一个MultiSet,因此您可以参考该库获取生产代码)。

import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeMap;

public class Bag<E> 
{
    private Map<E, Integer> m_values;

    public Bag()
    {
        m_values = new TreeMap<E, Integer>();
    }

    public Bag(Iterable<E> arr)
    {
        this();
        for(E v : arr)
        {
            add(v);
        }
    }

    public Bag(Bag<E> b)
    {
        this();
        for(E v : b.values())
        {
            set(v, b.count(v));
        }
    }

    public void add(E v)
    {
        Integer count = m_values.get(v);
        m_values.put(v, count == null ? 1 : count+1);
    }

    public void add(Bag<E> b)
    {
        for(E v : b.values())
        {
            Integer count = m_values.get(v);
            m_values.put(v, count == null ? b.count(v) : count+b.count(v));
        }
    }

    public void remove(E v)
    {
        Integer count = m_values.get(v);
        if(count == null) throw new NoSuchElementException();
        if(count == 1)
            m_values.remove(v);
        else
            m_values.put(v, count-1);
    }

    public void remove(Bag<E> b)
    {
        for(E v : b.values())
        {
            Integer count = m_values.get(v);    
            Integer bcount = b.count(v);
            if(count == null || count < bcount) throw new NoSuchElementException();
            if(count == bcount)
                m_values.remove(v);
            else
                m_values.put(v, count-bcount);
        }
    }

    public boolean contains(Bag<E> b)
    {
        for(E v : b.values())
        {
            if(count(v) < b.count(v)) return false;
        }
        return true;
    }

    public void set(E v, int count)
    {
        if(count == 0)
            m_values.remove(v);
        else
            m_values.put(v, count);
    }

    public int count(E v)
    {
        Integer count = m_values.get(v);
        return count == null ? 0 : count;
    }

    public Iterable<E> values()
    {
        return m_values.keySet();
    }

    public String toString()
    {
        StringBuilder b = new StringBuilder();
        b.append("[");
        for(E v : values())
        {
            for(int i=0; i<count(v); i++)
            {
                b.append(v + " ");
            }
        }
        b.deleteCharAt(b.length()-1);
        b.append("]");
        return b.toString();
    }
}

The first step in solving the problem is to generate a list of candidate sets that sum to 5. We could do this by generating subsets from the input array, but we have to be careful not to include duplicates. 解决问题的第一步是生成总计为5的候选集列表。我们可以通过从输入数组生成子集来做到这一点,但是我们必须注意不要包含重复项。 The code for this isn't too bad, but it's actually much easier, if a little less efficient, to just generate all possible partitions of the count you're interested in, in this case 5. 这样的代码还不错,但是实际上效率要低一些,它只是生成您感兴趣的计数的所有可能分区,在本例中为5。

import java.util.ArrayList;
import java.util.List;

public class Partition
{
    public static List<Bag<Integer>> partitions(int n)
    {
        return new Partition(n).partitions;
    }

    private List<Bag<Integer>> partitions;
    private Bag<Integer> current;

    private Partition(int n)
    {
        partitions = new ArrayList<>();
        current = new Bag<Integer>();
        build(n, n);
    }

    private void build(int n, int max)
    {
        if (n == 0)
        {
            partitions.add(0, new Bag<Integer>(current));
        }

        for (int i = Math.min(max, n); i >= 1; i--)
        {
            current.add(i);
            build(n - i, i);
            current.remove(i);
        }
    }

    public static void main(String[] args)
    {
        for (Bag<Integer> b : partitions(5))
        {
            System.out.println(b);
        }
    }
}

Output: 输出:

[1 1 1 1 1]
[1 1 1 2]
[1 2 2]
[1 1 3]
[2 3]
[1 4]
[5]

Now we can write a recursive routine to extract maximal sets of these partitions from your input. 现在,我们可以编写一个递归例程,以从您的输入中提取这些分区的最大集合。 The only tricky part is to ensure that when we find a set that it isn't a subset of a solution we've already seen, in which case we can ignore it. 唯一棘手的部分是确保当我们找到的集合不是我们已经看到的解决方案的子集时,在这种情况下我们可以忽略它。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Dice
{
    public static List<List<Bag<Integer>>> picks(Integer[] diceArr, int k)
    {
        return new Dice(diceArr, k).output;
    }

    private List<List<Bag<Integer>>> output;
    private List<Bag<Integer>> current; 
    private List<Bag<Integer>> partitions;
    private Bag<Integer> dice;

    private Dice(Integer[] diceArr, int k)
    {
        output = new ArrayList<>();
        current = new ArrayList<>();

        partitions = Partition.partitions(5);
        dice = new Bag<>(Arrays.asList(diceArr));

        build(0);
    }

    private void build(int pos)
    {
        for (int i=pos; i<partitions.size(); i++)
        {
            Bag<Integer> partition = partitions.get(i);

            if(dice.contains(partition))
            {
                dice.remove(partition);
                current.add(partition);
                build(i);
                current.remove(partition);              
                dice.add(partition);
            }           
        }

        // Only add the current list of partitions if we haven't already seen it
        if(!current.isEmpty())
        {
            boolean seen = false;
            for(List<Bag<Integer>> prev : output)
            {
                if(prev.containsAll(current)) 
                {
                    seen = true;
                    break;
                }
            }
            if (!seen) output.add(new ArrayList<>(current));
        }
    }

    public static void main(String[] args)
    {
        int count = 5;
        Integer[] dice = {1, 1, 1, 2, 4, 4};
        List<List<Bag<Integer>>> picks = picks(dice, count);
        for(List<Bag<Integer>> pick : picks)
        {
            System.out.println(pick);
        }
    }
}

Output for {1, 1, 1, 2, 4, 4}: {1、1、1、2、4、4}的输出:

    [[1 1 1 2]]
    [[1 4], [1 4]]

Output for {1, 1, 1, 2, 3, 4, 4, 4, 5}: {1,1,1,2,3,4,4,4,5}的输出:

[[1 1 1 2], [5]]
[[1 1 3], [1 4], [5]]
[[2 3], [1 4], [1 4], [1 4], [5]]

You can use a map to save results. 您可以使用地图保存结果。 If there's a duplicated result. 如果有重复的结果。 The map will not save it. 地图不会保存它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM