#c_sharp #алгоритм
n = 12 должно вывести 1+2+3+4+5+6+7+8+9+(1+0)+(1+1)+(1+2) Написал 2 программы, но пишет, из-за того что долго выполняются - процесс отменяется. То есть, их нужно оптимизировать, только вот КАК Код двух программ: using System; public class TwistedSum { public static long Solution(long n) { int res = 0; int ostatok = 0; int Part = 0; for (int i = 1; i <= n; i++) { if (i >=10) { Part = i; while (Part >= 0) { ostatok = Part % 10; Part = Part / 10; res = res + ostatok; } } else { res = res + i} } return res; } } (тут передается в n число, все нормально, просто только функция написана) 2ой код: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace codewarsSumaCifr { class Program { static void Main(string[] args) { long n = 10; Console.Write(Solution(n)); Console.ReadKey(); } public static long Solution(long n) { int res = 0; string str2 = ""; for (int i = 1; i <= n; i++) { str2 = str2 + i.ToString(); } for (int j = 0; j < str2.Length; j++) { res = res + (int)Char.GetNumericValue(str2[j]); } return res; } } }
Ответы
Ответ 1
Цикл, вообще не правильное решение, его надо свернуть, и решить задачу аналитически. Решать задачу целиком скучно, но идею, как она решается, подкину: 9: (0+0)+(0+1)+(0+2)+(0+3)+(0+4)+(0+5)+(0+6)+(0+7)+(0+8)+(0+9) = 45 19: (1+0)+(1+1) ... +(1+8)+(1+9) + 45 = 1*10 + 1*45 + 45 29: (2+0)+(2+1) ... +(2+8)+(2+9) + 2*45 + 1*10 = 2*10 + 1*10 + 2*45 + 45 ... 99: (9+0)+(9+1) ...+(9+9) + 9*45 + 8*10 ... + 1*10 = 9*10 + 8*10 ... + 1*10 + 9*45 + 45Ответ 2
Придумал алгоритм, который вычислит намного быстрее. Вычислительная сложность предыдущего ответа — O(n log(n)), тогда так сложность этого ответа — O(log(n)). Вот код, объяснение ниже. Процесс примерно так, как и в ответве Mirdin'a. public static long Solution(long n) { long sum = 0; long power = 1; while (power <= n) { long mod = n % (power * 10), remainder = (n - mod) / 10, digit = mod / power; sum += 45 * remainder + power * digit * (digit - 1) / 2 + digit * ((mod % power) + 1); power *= 10; } return sum; } Как это работает? Например, как узнать Solution(62345)? Считаем по каждой цифре: 62345: (0+1+2+3+4+5+6+7+8+9)*6234 + (0+1+2+3+4) + 5 62345: (0+1+2+3+4+5+6+7+8+9)*6230 + (0+1+2+3)*10 + 4*(5+1) 62345: (0+1+2+3+4+5+6+7+8+9)*6200 + (0+1+2)*100 + 3*(45+1) 62345: (0+1+2+3+4+5+6+7+8+9)*6000 + (0+1)*1000 + 2*(345+1) 62345: (0+1+2+3+4+5)*10000 + 6*(2345+1) Ещё замечаем, что 0+1+2+3+4+5+6+7+8+9 равно 45, и что 0+1+...+(k-1)равно k*(k-1)/2: 62345: 45*6234 + (5*4/2) + 5 62345: 45*6230 + (4*3/2)*10 + 4*(5+1) 62345: 45*6200 + (3*2/2)*100 + 3*(45+1) 62345: 45*6000 + (2*1/2)*1000 + 2*(345+1) 62345: (6*5/2)*10000 + 6*(2345+1) В сумме, получится 1276185.Ответ 3
Первая программа почти правильное, только у вас бесконечный цикл while (Part >= 0). Можно делать так, немного по проще: public static long Solution(long n) { long sum = 0; for (long i = 1; i <= n; i++) { long j = i; while (j > 0) { sum += j % 10; j /= 10; } } return sum; } Кстати, это последовательность A037123 в OEIS.Ответ 4
У вас бесконечный цикл. while (Part >= 0) при том, что Part инициализируется 1, а потом ее можно очень долго делить на 10, всегда будет больше 0 UPD Part = Part / 10; Всегда будет больше 0, и из цикла while (Part >= 0) вы никогда не выйдете.Ответ 5
Вот ещё один рекурсивный вариант, проходящий по цифрам, с мемоизацией. Вычислительная сложность также должна быть по идее логарифмическая. // вспомогательная функция: сумма цифр static int SumOfDigits(int n) { int result = 0; while (n > 0) { result += n % 10; n /= 10; } return result; } // главная функция public static int F(int n) { // выход из рекурсии для чисел меньше 10 if (n < 10) return F1(n); int result = 0; // обрабатываем по одной цифре справа налево // для маски 10000 текущее число будет иметь форму xyz..t0000 for (int mask = 1; n > 0; mask *= 10) { // выбираем число t0000 int lastPart = n % (mask * 10); // делим его на цифру и степень result += FDigitTimesPowerOfTen(lastPart / mask, mask); // убираем обработанную цифру n -= lastPart; // компенсация: на каждом числе из убранной части // нужно добавить цифры остатка result += lastPart * SumOfDigits(n); } return result; } // вычисление функции для числа вида t00000 // в этом случае digit = t, mask = 10000 (степень десятки) static int FDigitTimesPowerOfTen(int digit, int mask) { if (digit == 0) return 0; // заменяем все старшие цифры на 0 // при этом для компенсации добавляем 1000...0 раз убранные цифры // то есть F1(digit - 1) return FPowerOfTen(mask) * digit + F1(digit - 1) * mask; } // кэш для степеней десятки static DictionaryFPowerOfTenCache = new Dictionary (100) { { 1, 1 } }; // вычисление функции для степеней десятки static int FPowerOfTen(int n) { int result; if (!FPowerOfTenCache.TryGetValue(n, out result)) { // n-1 имеет на одну цифру меньше, спускаемся рекурсивно result = 1 + F(n - 1); FPowerOfTenCache[n] = result; } return result; } // функция для одноцифрового числа - сумма арифметической прогрессии static int F1(int n) { Debug.Assert(0 <= n && n < 10); return n * (n + 1) / 2; }
Комментариев нет:
Отправить комментарий