Sorted Lexical Partition of a Number
Pyth, 34
FNyUz#aYmv:zhdedC,+0N+NlzB)efqSTTY
Try it online here. Notice, this has a time (and space) complexity of O(n). Therefore the test case 12345678901234567890
takes too long in the online compiler. Use the offline one instead (1 minute on my laptop).
This is only my first attempt. There might be some room for improvements.
First some ideas how my algorithm works.
- I interpret the input as string and not as a number.
- Then I create all possible subsets of
[0, 1, 2, ..., len(n-1)]
- For each of these subsets (lets take
[1, 4, 5]
), I split the input string into part using these numbers.[input[0:1], input[1, 4], input[4,5], input[5,len(input)]]
. - Afterwards I try to convert these numbers into strings. There can be two problems. Pyth (or Python) throws an exception for an empty string, and for a string of numbers starting with
0
. Therefore I use atry - catch
block (actually infinity loop with an immediate break). If converting was successfully, I add the result to a listY
. - After I handled all subsets, I filter the list
Y
for results, that are already sorted and print the last one (the last one has the most groups).
Now the detailed explanation:
Implicit: z = input() (z is a String!)
Y = empty list
FNyUz for each subset N of [0, 1, 2, ..., len(z)-1]:
# start try-catch block (actually an infinite loop,
but the Python implementation uses a try catch.
aY append to Y:
C,+0N+Nlz zip([0] + N, N + [len(z)])
m map each element d to
:zhded z[d[0]:d[-1]]
v evaluated
B if this didn't throw an exception already, end the infinite loop
) end for loop
f Y filter Y for elements T, for which
qSTT sorted(T) == T
e and print the last one (the subsets generated with yUz are sorted
by length, so the last one has the most groups)
Mathematica, 134 127 bytes
This is pretty inefficient since it generates a lot more partitions than the valid ones. The 324142434445
test case runs within a few seconds, but I wouldn't try 12345678901234567890
.
f/@Last@Select[Needs@"Combinatorica`";f=FromDigits;SetPartitions[d=IntegerDigits@#],0<=##&@@f/@#&&Join@@#==d&&#~FreeQ~{0,__}&]&
This defines an unnamed function which takes an integer and returns a list of integers.
Explanation
The reading order of this code is a bit all over the place, so I'll break down in the order it's intended to be read (and evaluated for the most part):
d=IntegerDigits@#
get the decimal digits of the input and assign this list tod
.SetPartitions
(which requiresNeeds@"Combinatorica`";
) gives me all partitions of this. However, it returns a lot more than I actually want since it treats the input as a set. This is what makes it inefficient, but I'm using this because the shortest way I know to get all list partitions is much longer. As an example, if the list was{1, 2, 3}
the function would return:{{{1, 2, 3}}, {{1}, {2, 3}}, {{1, 2}, {3}}, {{1, 3}, {2}}, {{1}, {2}, {3}}}
Note that a) the consecutive partitions are all in the right order and b) the partitions are sorted from coarsest to finest.
Select[...,...&]
then filters this list by the anonymous function passed in as the second argument.Join @@ # == d
checks that we've actually got a list partition instead of a general set partition.#~FreeQ~{0, __}
checks that no partition starts with a leading zero.0 <= ## & @@ f /@ #
is a bit more obscure. First we mapFromDigits
onto each list in the partition to recover the numbers represented by the digits. Then we apply0 <= ##
to those numbers, where##
refers to all the numbers. If the partition is{1, 23, 45}
then this expands to0 <= 1 <= 23 <= 45
, so it checks that the array is sorted.
Last@
then gives me the last partition left after filtering - this works becauseSetPartitions
already sorted the partitions, such that the finest ones are at the end.- Finally,
f/@
recovers the numbers from the digit lists.
Python 3, 134 bytes
def f(s,n=0,L=[],R=[],i=0):
while s[i:]:i+=1;m=int(s[:i]);R=max([f(s[i:],m,L+[m]),R][m<n or"1">s[i:]>"":],key=len)
return[L,R][s>""]
It's a little messy, but oh well. The program just generates all valid partitions recursively. The interesting part is that to disallow leading zeroes, all that was necessary was an additional or "1">s[i:]>""
condition.
Takes input like f("12345678901234567890")
and returns a list of ints.