Make the biggest and smallest numbers Inspired by this post over on Puzzling. Spoilers for that puzzle are below.

Given three positive integers as input, (x, y, z), construct the inclusive range [x, y], concatenate that range together, then remove z not-necessarily-consecutive digits to produce the largest and smallest positive integers possible. Leading zeros are not permitted (i.e., the numbers must start with [1-9]). Output those two numbers in either order.

For the example from the Puzzling post, for input (1, 100, 100), the largest number possible is 99999785960616263646566676869707172737475767778798081828384858687888990919293949596979899100,
and the smallest number is 10000012340616263646566676869707172737475767778798081828384858687888990919293949596979899100,
following the below logic from jafe's answer posted there:


We can't influence the number's length (there's a fixed number of digits), so to maximize the value we take the maximal first digit, then second digit etc.
Remove the 84 first non-nines (16 digits left to remove):
999995051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
The largest number within the next 17 digits is 7, so from here, the next digit in the answer can be at most 7 (we can't remove more than 16 digits). So remove 15 non-7's... (1 digit left to remove): 999997585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
From here, the next digit can be at most 8 so remove one non-8 from the middle: 99999785960616263646566676869707172737475767778798081828384858687888990919293949596979899100
Similar logic, but reversed (i.e., we want leading 1s instead of leading 9s) for the smallest number.


Here's a smaller example: (1, 10, 5).

We construct the range 12345678910 and determine which 5 digits we can remove leaving the largest possible number. Obviously, that means we want to maximize the leading digit, since we can't influence the length of the output. So, if we remove 12345, we're left with 678910, and that's the largest we can make. Making the smallest is a little bit trickier, since we can pluck out numbers from the middle instead, leaving 123410 as the smallest possible.

For (20, 25, 11), the result is rather boring, as 5 and 1.

Finally, to rule out answers that try leading zeros, (9, 11, 3) gives 91011 which in turn yields 91 and 10 as the largest and smallest.

I/O and Rules


If it's easier/shorter, you can code two programs/functions -- one for the largest and one for the smallest -- in which case your score is the sum of both parts.
The input and output can be given by any convenient method.
The input can be assumed to fit in your language's native number type, however, neither the concatenated number nor the output can be assumed to do so.
Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
Standard loopholes are forbidden.
This is code-golf so all usual golfing rules apply, and the shortest code (in bytes) wins.
Haskell, 162 bytes



l=length
((m,f)%n)s|n&gt;=l s=[]|n&gt;0,(p,c:r)&lt;-span(/=m(f$take(n+1)s))s=c:((m,id)%(n-l p)$r)|1&gt;0=s
(x#y)z=[p%z$show=&lt;&lt;[x..y]|p&lt;-[(maximum,id),(minimum,filter(&gt;'0'))]]


Try it online!

Uses the algorithm described by jafe. Might be shorter to use a less efficient method, but this was more fun to write :)

The % operation takes 4 arguments (actually 3, but whatever): m which is a function that selects the "optimal" member from a list (either maximum or minimum depending on what we want); f which is a "filter" function; n the number of digits left to drop; and s the string. First we check whether n is equal to the number of digits left in the string (I used &gt;= for safety) and drop the rest of s if so. Otherwise we check if we still need to drop digits (n&gt;0), then we use span to break our string into three pieces: p the digits to drop, c the optimal reachable digit, and r the remaining string. We do this by passing span a predicate that checks for equality against our optimal digit. To find that digit we take the first n+1 digits of the string, filter it, then pass it to our "chooser" function. Now we just yield our optimal digit and recur, subtracting the length of p (the number of digits dropped) from n. Notice that we do not pass our filtering function to the recursive call, and, instead, we replace it with id. That's because the filter is only there to avoid selecting leading 0s in the minimum case which is only relevant on the first iteration. After that we no longer need any filter.

% is really only a helper function for # which is our "real" function, taking x, y, and z. We use a list comprehension just to avoid a bit of repetition, iterating over our function tuples and passing them to % along with z and the concatenated string. That string is created using the magic monad operator (=&lt;&lt;) which, in this context, works like concatMap.