加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 0-9一次使用每个数字可以形成的任何(2)数字的最小差异是什

发布时间:2020-12-15 20:59:09 所属栏目:百科 来源:网络整理
导读:假设你有数字= {0,..,9}. 假设您有一个输入,它是基数至少为2的数字子集. 考虑所有可能的基数10整数对a和b,使得输入中的每个元素在a或b中使用一次并且没有前导0(但实际值0是可以的). Solve算法找到输入中所有有效对的差值的绝对值的最小值. 例如,如果input =
假设你有数字= {0,..,9}.

假设您有一个输入,它是基数至少为2的数字子集.

考虑所有可能的基数10整数对a和b,使得输入中的每个元素在a或b中使用一次并且没有前导0(但实际值0是可以的).

Solve算法找到输入中所有有效对的差值的绝对值的最小值.

例如,如果input = {0,1,2,4,6,7}.

有很多可能的对使用每个数字恰好一次,例如a = 210和b = 764以及a = 204和b = 176.

事实证明,第二对具有最小绝对值差(28).

输入将作为字符串提供给名为Solve的静态方法,每个数字按单个空格按升序分隔.您可以假设输入有效并已排序.

问题:Solve的正确C#实现具有最佳运行时间(不需要单独预先计算/硬编码每个~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;
    }
}

(这个问题最近被其他用户询问,但似乎已被用户删除;但我已经想出了一个答案,所以我不想让它失去它.我重新措辞并重新格式化了问题,稍微.)

解决方法

这个答案还没有被证明是最佳的,所以我不接受它 – 随意改进它或发布一个更好的答案!

我在这个问题的评论中从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's 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,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;
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读