7

This seems like a simple request, but google is not my friend because "partition" scores a bunch of hits in database and filesystem space.

I need to enumerate all partitions of an array of N values (N is constant) into k sub-arrays. The sub-arrays are just that - a starting index and ending index. The overall order of the original array will be preserved.

For example, with N=4 and k=2:

[ | a b c d ] (0, 4)
[ a | b c d ] (1, 3)
[ a b | c d ] (2, 2)
[ a b c | d ] (3, 1)
[ a b c d | ] (4, 0)

And with k=3:

[ | | a b c d ] (0, 0, 4)
[ | a | b c d ] (0, 1, 3)
  :
[ a | b | c d ] (1, 1, 2)
[ a | b c | d ] (1, 2, 1)
  :
[ a b c d | | ] (4, 0, 0)

I'm pretty sure this isn't an original problem (and no, it's not homework), but I'd like to do it for every k <= N, and it'd be great if the later passes (as k grows) took advantage of earlier results.

If you've got a link, please share.

Chris Gerken
  • 15,735
  • 6
  • 41
  • 58
Austin Hastings
  • 587
  • 3
  • 13
  • 2
    It looks straightforward with k = 2; can you post an example with a higher k, for preferably a higher value of n, so that the question would be more clear? – Amarghosh Dec 30 '10 at 14:53
  • 1
    Your example has the same partition for (0, 4) and (4, 0) namely, abcd is that intended? – Andrew White Dec 30 '10 at 15:14
  • Andrew, the partitions are different. One is |abcd and the other is abcd| (the empty bit is at opposite ends). – Austin Hastings Dec 30 '10 at 15:49

2 Answers2

7

In order to re-use the prior results (for lesser values of k), you can do recursion.

Think of such partitioning as a list of ending indexes (starting index for any partition is just the ending index of the last partition or 0 for the first one).

So, your set of partitionings are just a set of all arrays of k non-decreasing integers between 0 and N.

If k is bounded, you can do this via k nested loops

for (i[0]=0; i[0] < N; i[0]++) {
    for (i[1]=i[0]; i[1] < N; i[1]++) {
    ...
            for (i[10]=i[9]; i[10] < N; i[10]++) {
                push i[0]==>i[10] onto the list of partitionings.
            }
    ...
    }
}

If k is unbounded, you can do it recursively.

A set of k partitions between indexes S and E is obtained by:

  • Looping the "end of first partition" EFP between S and E. For each value:

    • Recursively find a list of k-1 partitions between EFP and S

    • For each vector in that list, pre-pend "EFP" to that vector.

    • resulting vector of length k is added to the list of results.

Please note that my answer produces lists of end-points of each slice. If you (as your example shows) want a list of LENGTHS of each slice, you need to obtain lengths by subtracting the last slice end from current slice end.

DVK
  • 119,765
  • 29
  • 201
  • 317
0

Each partition can be described by the k-1 indexes separating the parts. Since order is preserved, these indices must be non-decreasing. That is, there is a direct correspondence between subsets of size k-1 and the partitions you seek.

For iterating over all subsets of size k-1, you can check out the question:

How to iteratively generate k elements subsets from a set of size n in java?

The only wrinkle is that if empty parts are allowed, several cut-points can coincide, but a subset can contain each index at most once. You'll have to adjust the algorithm slightly by replacing:

        processLargerSubsets(set, subset, subsetSize + 1, j + 1);

by

        processLargerSubsets(set, subset, subsetSize + 1, j);
Community
  • 1
  • 1
meriton
  • 61,876
  • 13
  • 96
  • 163