c# – 0-9一次使用每个数字可以形成的任何(2)数字的最小差异是什
假设你有数字= {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; } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |