简体   繁体   中英

Given an array of integers find all “maximal” subsets

Given an upper bound d and an array of integers, return all subsets (as arrays) whose sum of elements is <= d and to whom we can't add any other element from the array such that <= d is not violated.

Example:

d = 4;
int[] arr = {1, 2, 3, 4, 5};

int[][] solution = findAllMaximalSubsets(arr, d);

System.out.println(Arrays.deepToString(solution));

Output: { {1, 2}, {1, 3}, {4} }

This method findAllMaximalSubsets(int[] arr, d) is a subroutine in another algorithm I'm working on. I suspect that the solution will be Np-ish which is fine.

Currently I have no approach to tackle this problem :/

Not disagreeing with the comments that say Stack Overflow is not the place where code is written for you. I think I can explain the details better and more precisely in code than in words, so I do provide code here. Also I admit it was a pleasure writing it (which in itself is no excuse for also posting it).

I am not using any dynamic programming nor any graph here. I am using the idea of Dawood Ibn Kareem of trying with and without x and using recursion for the remainder of the problem.

In each call to the recursive method I am passing the array, a , and the upper bound, capacity ; these are the same in every call. I pass a partial solution telling which of the previously considered elements are included in the subset currently being built, and the sum of the included elements just for convenience. Finally I pass the smallest element left out so far. This will allow me to check in the end whether we end up with a set where we cannot add another element.

I am not giving you the return type you expected, but I trust you to convert yourself if it's important. The reason is I assumed array elements are distinct even if some are equal. If the array is { 1, 3, 2, 3, 5 } and the solution includes { 1, 3 } , you don't know which of the 3s I took. So instead I give you a boolean array of either { true, true, false, false, false } (if I took the first 3) or { true, false, false, true, false } (if I took the second 3) (in practice I will give you both).

/**
 * Calculates all subsets of a that have a sum <= capacity
 * and to which one cannot add another element from a without exceeding the capacity.
 * @param a elements to put in sets;
 * even when two elements from a are equal, they are considered distinct
 * @param capacity maximum sum of a returned subset
 * @return collection of subsets of a.
 * Each subset is represented by a boolean array the same length as a
 * where true means that the element in the same index in a is included,
 * false that it is not included.
 */
private static Collection<boolean[]> maximalSubsetsWithinCapacity(int[] a, int capacity) {
    List<boolean[]> b = new ArrayList<>();
    addSubsets(a, capacity, new boolean[0], 0, Integer.MAX_VALUE, b);
    return b;
}

/** add to b all allowed subsets where the the membership for the first members of a is determined by paritalSubset
 * and where remaining capacity is smaller than smallestMemberLeftOut
 */
private static void addSubsets(int[] a, int capacity, boolean[] partialSubset, int sum,
        int smallestMemberLeftOut, List<boolean[]> b) {
    assert sum == IntStream.range(0, partialSubset.length)
            .filter(ix -> partialSubset[ix])
            .map(ix -> a[ix])
            .sum() 
            : Arrays.toString(a) + ' ' + Arrays.toString(partialSubset) + ' ' + sum;
    int remainingCapacity = capacity - sum;
    if (partialSubset.length == a.length) { // done
        // check capacity constraint: if there’s still room for a member of size smallestMemberLeftOut,
        // we have violated the maximality constraint
        if (remainingCapacity < smallestMemberLeftOut) { // OK, no more members could have been added
            b.add(partialSubset);
        }
    } else {
        // try next element from a.
        int nextElement = a[partialSubset.length];
        // i.e., decide whether  should be included.
        // try with and without.

        // is including nextElement a possibility?
        if (nextElement <= remainingCapacity) { // yes
            boolean[] newPartialSubset = Arrays.copyOf(partialSubset, partialSubset.length + 1);
            newPartialSubset[partialSubset.length] = true; // include member
            addSubsets(a, capacity, newPartialSubset, sum + nextElement, smallestMemberLeftOut, b);
        }

        // try leaving nextElement out
        boolean[] newPartialSubset = Arrays.copyOf(partialSubset, partialSubset.length + 1);
        newPartialSubset[partialSubset.length] = false; // exclude member
        int newSmallestMemberLeftOut = smallestMemberLeftOut;
        if (nextElement < smallestMemberLeftOut) {
            newSmallestMemberLeftOut = nextElement;
        }
        addSubsets(a, capacity, newPartialSubset, sum, newSmallestMemberLeftOut, b);
    }

It's slightly tricky in a few spots. I hope my comments will help you through it. Otherwise please ask.

Let's try it out:

    int[] a = { 5, 1, 2, 6 };
    Collection<boolean[]> b = maximalSubsetsWithinCapacity(a, 8);
    b.forEach(ba -> System.out.println(Arrays.toString(ba)));

This code prints:

[true, true, true, false]
[false, true, false, true]
[false, false, true, true]
  • [true, true, true, false] means a subset of 5, 1 and 2. The sum is 8, so this fits the capacity of 8 exactly ( d ).
  • [false, true, false, true] means 1 and 6, sum is 7 and we could not add 2 or we would exceed the capacity
  • finally [false, false, true, true] means 2 and 6 and also fits the capacity d exactly.

I believe this exhausts the possibilities within your constraints.

May be you can find all the combination of subset like below and add all subset elements and compare with d.

===================

  private static void findAllMaximalSubsets(int[] arr,int d) {


   for(int i=0;i<arr.length;i++) {
       for (int j =i;j< arr.length;j++) {
           int sum = 0;
           for (int k = i; k <= j; k++) {
               sum = sum + arr[k];
           }
           if (sum <= d) 
               //add the array elements from k o j to the 2D arry
       }
   }    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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