What is the smallest difference in any (2) numbers that can be formed using each digit after 0-9?

Suppose you have numbers = {0,..,9}.

Suppose you have an input , which is a subset of digits with a capacity of at least 2.

Consider all possible pairs of as many as 10 bases a and b , so that each input element is used once in a or b and without a lead 0(the actual value 0is fine, though).

The algorithm Solvefinds the minimum value of the absolute value of the difference of all valid pairs from the input.

For example, if you enter = { 0, 1, 2, 4, 6, 7 }.

There are many possible pairs that use each digit exactly once, for example a = 210and b = 764and a = 204and b = 176.

As it turned out, the second pair has a minimum difference in absolute values ​​( 28).

the input will be provided to a method staticcalled Solvein the form of a string with each digit divided by one space in ascending order. You can assume that the input is valid and sorted.

Question: What is the correct C # implementation Solvehas the best execution time (without preliminary calculation / hard coding of each solution ~2^10)?

, , ( , ). , , "" , "" .):

class Program
{
    static void Main(string[] args)
    {
        var input = "0 1 2 4 6 7";
        var result = Solve(input);
    }

    private static int Solve(string input)
    {
        var digits = input.Split(' ').Select(i => int.Parse(i)).ToArray();
        return GetSmallestDifference(digits) ?? -1;
    }

    public static int? GetSmallestDifference(IEnumerable<int> input)
    {
        var validInput = ValidateInput(input);

        var candidates = GenerateCandidates(validInput);

        int? best = null;
        foreach (var candidate in candidates)
        {
            var current = Math.Abs(candidate.Item1 - candidate.Item2);
            if (current < (best ?? int.MaxValue))
            {
                best = current;
            }
        }
        return best;
    }

    private static IEnumerable<Tuple<int, int>> GenerateCandidates(int[] validInput)
    {
        var found = new HashSet<string>();

        var nonZeroDigits = validInput.Except(new[] { 0 });
        var max = int.Parse(string.Join("", nonZeroDigits.OrderByDescending(i => i)));
        for (int i = 0; i <= max; i++)
        {
            var potential = i;
            var complements = GetComplements(potential, validInput);
            if (complements != null)
            {
                foreach (var complement in complements)
                {
                    var signature = GetSignature(potential, complement);
                    if (!found.Contains(signature))
                    {
                        found.Add(signature);

                        yield return Tuple.Create(potential, complement);
                    }
                }
            }
        }
    }

    private static string GetSignature(int potential, int complement)
    {
        // Sort it so we don't get duplicates.
        var key = new[] { potential, complement }.OrderBy(i => i).ToArray();
        var formatted = string.Format("{0} {1}", key[0], key[1]);
        return formatted;
    }

    private static List<int> GetComplements(int potential, int[] validInput)
    {
        var remaining = validInput.ToList();
        var digits = potential.ToString().Select(c => int.Parse(c.ToString())).ToArray();

        foreach (var d in digits)
        {
            // This means the potential isn't a valid candidate.
            if (!remaining.Contains(d))
            {
                return null;
            }

            remaining.Remove(d);
        }

        // This means there were no other digits to choose.
        if (remaining.Count == 0)
        {
            return null;
        }
        else
        {
            var complements = new List<int>();
            Scramble(complements, "", remaining);
            return complements;
        }
    }

    private static void Scramble(List<int> complements, string result, IEnumerable<int> remaining)
    {
        if (remaining.Any())
        {
            foreach (var i in remaining)
            {
                var childResult = result + i;
                var childRemaining = remaining.Except(new[] { i });

                Scramble(complements, childResult, childRemaining);
            }
        }
        else
        {
            if (!result.StartsWith("0") || result.Length == 1)
            {
                var intResult = int.Parse(result);
                complements.Add(intResult);
            }
        }
    }

    private static int[] ValidateInput(IEnumerable<int> input)
    {
        // Make sure (2) integers were entered.
        if (input == null || input.Count() < 2)
        {
            // TODO
            throw new Exception();
        }

        // Make sure you don't have duplicates.
        var result = input.Distinct().ToArray();

        // Make sure the numbers are in range.
        if (result.Min() < 0 || result.Max() > 9)
        {
            // TODO
            throw new Exception();
        }

        return result;
    }
}

( , , , , , , SO . , .)

+4
3

, , - !

KooKiz . ( == , , , , ), , <100ms , ( ).

class SneakierProgram
{
    static void Main(string[] args)
    {
        var input = "0 1 2 4 6 7";
        var result = Solve(input);
    }

    private static int Solve(string input)
    {
        int? best = null;
        int a, b;

        var unvalidatedDigits = input.Split(' ').Select(i => int.Parse(i));

        var digits = ValidateInput(unvalidatedDigits);

        // Special case because the even algorithm doesn't play nicely if there are exactly (2)
        // digits and one of them is 0.
        if (digits.Length == 2)
        {
            // However since it already sorted and there are only 2 digits we know what to do.
            best = digits[1] - digits[0];
        }
        else if (digits.Length % 2 == 1)
        {
            // Are there an odd number of digits to choose from?
            // If so the most sigificant needs to be 0 for the smaller number.
            var b0 = 0;

            // That forces the most sigificant needs to be the minimum non-0 for the larger number.
            var a0 = digits.Except(new[] { 0 }).Min();

            // The 0 for b0 doesn't count/shouldn't be excluded.
            // Note remaining now has an even number of digits left.
            var remaining = digits.Except(new[] { a0 });
            OptimizeRemainingDigits(remaining, a0, b0, out a, out b);

            best = a - b;
        }
        else
        {
            // There are an even number of digits to choose from, so each number will contain
            // an equal number of digits.  The most sigificant digits most affect the difference
            // so minimizing them is our greatest concern.  Since the array is sorted we only
            // need to consider adjacent pairs.

            var nonZeroDigits = digits.Except(new[] { 0 }).ToArray();

            // There will be one less adjacent pair than the total to choose from.
            var adjacentPairIndices = Enumerable.Range(0, nonZeroDigits.Length - 1);

            // Project the adjacent pairs.
            var adjacentPairs = adjacentPairIndices.Select(i => new
            {
                // The larger will be one past the index.
                Larger = nonZeroDigits[i + 1],
                // The smaller will be at the index.
                Smaller = nonZeroDigits[i]
            });

            // Group adjacent pairs by their difference.
            var groupedAdjacentPairs = adjacentPairs.ToLookup(pair => pair.Larger - pair.Smaller);

            // Find the minimum difference.
            var minimumDifference = groupedAdjacentPairs.Select(g => g.Key).Min();

            // Consider only the adjacent pairs that have minimum difference.
            var candidates = groupedAdjacentPairs[minimumDifference];
            foreach (var candidate in candidates)
            {
                // The most sigificant needs to be smaller for the smaller number.
                var b0 = candidate.Smaller;

                // The most sigificant needs to be larger for the larger number.
                var a0 = candidate.Larger;

                // Both used digits need to be excluded.
                // Note remaining still has an even number of digits left.
                var remaining = digits.Except(new[] { a0, b0 });
                OptimizeRemainingDigits(remaining, a0, b0, out a, out b);

                var possibleBetter = a - b;
                if (possibleBetter < (best ?? int.MaxValue))
                {
                    best = possibleBetter;
                }
            }

        }

        return best ?? -1;
    }

    private static void OptimizeRemainingDigits(
        IEnumerable<int> remaining, 
        int a0, 
        int b0, 
        out int a, 
        out int b)
    {
        // Acculmuate the digits of a on a string.
        var aString = a0.ToString();

        // Acculumate the digits of b on a string (b can be 0, in which case don't count that as a digit).
        var bString = b0 == 0 ? "" : b0.ToString();

        // Each number will get half the remaining digits.
        var digitsPerNumber = remaining.Count() / 2;

        // The larger number gets the smaller digits from least to greatest 
        // to minimize its overall value.
        aString += string.Join("", remaining.
            OrderBy(i => i).Take(digitsPerNumber));

        // The smaller number gets the larger digits from greatest to least 
        // to maximize its overall value.
        bString += string.Join("", remaining.
            OrderByDescending(i => i).Take(digitsPerNumber));

        a = int.Parse(aString);
        b = int.Parse(bString);
    }

    private static int[] ValidateInput(IEnumerable<int> input)
    {
        // Make sure at least (2) integers were entered.
        if (input == null || input.Count() < 2)
        {
            // TODO
            throw new Exception();
        }

        // Make sure you don't have duplicates.
        var result = input.Distinct().ToArray();

        // Make sure the numbers are in range.
        if (result.Min() < 0 || result.Max() > 9)
        {
            // TODO
            throw new Exception();
        }

        return result;
    }
}
0

: , {1, 2, 3, 4, 6, 7}
, , - Hi-low , :

  • : 2--
  • lo: 1 -

, hi lo ( ), hi

[17_][23_] -> [176][234]

, , ,

...

( , )
hi lo, (lo 0):

Sample on {0,1,2,4,6} -> remove zero {1,2,4,6} -> choose 1 & 6  
[1__]  
[_6_]  
-> readd zero {0,2,4}
-> take turn add to hi, lo
-> [102][_64]

...

, . , GAP , GAP :

(a, b), a <
(a, b) - 1 ====== > GAP (a, b) = b - a

====== > GAP (a, b) = (10-b) + a

1 , hi lo

{6, 7, 8, 9}

level-1   | [6,7]:1 | [7,8]:1  | [8,9]:1  | same gap, cant decide best pair
sub-level | {8,9}:9 | {6,9}:7* | {6,7}:9  | pair[1] have smallest gap, trace back level-1
We now use [7,8] for our lo & hi first digits
hi[8_]    >run normal strategy>     hi[86]
lo[7_]                              lo[79]

1 , , ,

    void Solve()
    {
        int[] inputs = { 6, 7, 8, 9 }; //Make sure its sorted
        LinkedList<int> digitPool = new LinkedList<int>(inputs);
        Queue<int> hi = new Queue<int>();
        Queue<int> lo = new Queue<int>();

        ChooseFirstDigit(hi, lo, digitPool);

        bool flag = true;
        while (digitPool.Count != 0)
        {
            if (flag)
            {
                hi.Enqueue(digitPool.First());
                digitPool.RemoveFirst();
                flag = !flag;
            }
            else
            {
                lo.Enqueue(digitPool.Last());
                digitPool.RemoveLast();
                flag = !flag;
            }
        }

        while (hi.Count != 0)
            Console.Write(hi.Dequeue());
        Console.WriteLine("");
        while (lo.Count != 0)
            Console.Write(lo.Dequeue());
    }

    void ChooseFirstDigit(Queue<int> hi, Queue<int> lo, LinkedList<int> digitPool)
    {
        bool hasZero = false;
        bool oddCount = (digitPool.Count % 2 != 0);

        // { 0, 1, 2, 4, 6, 7, 8}
        if (digitPool.First() == 0)
        {
            hasZero = true;
            digitPool.RemoveFirst(); // {1, 2, 4, 6, 7}
        }

        if (oddCount)
        {
            hi.Enqueue(digitPool.First());              
            lo.Enqueue(digitPool.Last());
            digitPool.RemoveFirst();
            digitPool.RemoveLast();
        }
        else
        {
            var bestPair = digitPool.First;
            List<int> minGap = calculateGap(bestPair, hasZero);

            var pair = bestPair.Next; //pair[0,1]
            while (pair != digitPool.Last)
            {
                List<int> gap = calculateGap(pair, hasZero);
                for (int i = 0; i < gap.Count; ++i)
                {
                    if (gap[i] < minGap[i])
                    {
                        //found a better pair
                        minGap = gap;
                        bestPair = pair;
                        break;
                    }
                    else if (minGap[i] < gap[i])
                        break;
                }

                pair = pair.Next;               
            }

            lo.Enqueue(bestPair.Value);
            hi.Enqueue(bestPair.Next.Value);
            digitPool.Remove(bestPair.Next);
            digitPool.Remove(bestPair);
        }       

        if (hasZero) digitPool.AddFirst(0);
    }

    List<int> calculateGap(LinkedListNode<int> bestPair, bool hasZero)
    {
        LinkedList<int> clonedPool = new LinkedList<int>(bestPair.List);
        clonedPool.Remove(bestPair.Value);
        clonedPool.Remove(bestPair.Next.Value);

        List<int> gap = new List<int>();
        gap.Add(bestPair.Next.Value - bestPair.Value); //Level-1 GAP


        if (hasZero) clonedPool.AddFirst(0);

        while (clonedPool.Count != 0) //Sub-level GAPs
        {
            gap.Add((10 - clonedPool.Last()) + clonedPool.First());
            clonedPool.RemoveFirst();
            clonedPool.RemoveLast();
        }

        return gap;
    }
0

The choice of order and group according to increasing negative difference:

{0,1,2,4,6,7}

{[0-7],[0-6,1-7],[1-6,2-7],[0-4,2-6]
,[1-4,4-7],[0-2,2-4,4-6],[0-1,1-2,6-7]}

Assuming an even entry, the leftmost digit will be selected from the last group; the rest, from first to last:

While groups are not emptied, holding candidates for each spot 
from left to right, choose the right-most digit you can and proceed left:

There are two choices for the left-most digit but only one for the second 
digit, which dictates 2-1,0-7 and the only remaining digits, 4-6

Another example:

{6,7,8,9}

{[6-9],[6-8,7-9],[6-7,7-8,8-9]}

Again, only one choice for the second digit, which dictates 8-7,6-9
0
source

All Articles