C# 计算国王将金币作为工资,发放给忠诚的骑士

题目描述

国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到-枚金币:之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收到四枚金...这种工资发放模式会一直这样延续下去: 当连续n天每天收到n枚金币后,骑士会在之后的连续n + 1天里,每天收到n+ 1枚金币。

请计算在前k天里,骑士一共获得了多少金币。
C# 计算国王将金币作为工资,发放给忠诚的骑士_第1张图片

 思路:

我们将金币相同的看成一组,例如:122333444455555...,把1看成一组,22看成一组,333看成一组,4444看成一组,55555看成一组

如果计算天数6在哪一组?1+2+3=6,显然在3的那一组,金币就是1+2*2+3*3=14

如果计算天数100在哪一组?1+2+3+4+5+6+7+8+9+10+11+12+13+14=105>100,显然在14的那一组,金币就是1+2*2+3*3+...+13*13=sum,然后加上剩余的,1+2+3+4+5+6+7+8+9+10+11+12+13=(1+13)*13/2=91,sum=sum+(100-91)*14=945

代码如下:

         static int CalculateGoldCoins(int k)
        {
            if (k <= 0)
                return 0;
            int i, surplus, sum = 0, flag = 0;
            // 寻找在哪一组
            for (i = 1; i <= k; i++)
            {
                sum += i;
                if (sum >= k)
                {
                    //目标组
                    flag = i;
                    break;
                }
            }
            if (sum > k)// 超过了
            {
                sum = 0;
                surplus = flag - 1;
                // 计算剩余金币
                sum += (k - ((1 + surplus) * surplus >> 1)) * flag;
            }
            else
            {
                sum = 0;
                surplus = flag;
            }
            // 计算总共金币
            for (i = 1; i <= surplus; i++)
            {
                sum += i * i;
            }
            return sum;
        }

但是在计算总共金币时容易溢出(i*i 容易溢出),所以考虑将计算总共金币的代码换成以下优化计算总共金币的代码。

我们来考虑优化,对于寻找在哪一组其实很简单,如果计算天数100在哪一组?1+2+3+4+5+6+7+8+9+10+11+12+13+14=105>100,对于1+2+3+4+5+6+7+8+9+10+11+12+13+14=(1+14)*14/2=105这里可以优化,假设它在第n组,那么就是(1+n)*n/2>=k(k是天数),解出n>=(-1+\sqrt{1+8k})/2,再就是1^2+2^2+3^2+...+n^2=n(n+1)(2n+1)/6,代码如下:

        static int CalculateGoldCoins2(int k)
        {
            if (k <= 0)
                return 0;
            // 寻找在哪一组
            int n = (int)Math.Ceiling((-1 + Math.Sqrt(1 + (k << 3)))/2);
            int sum = 0, i, temp=0;
            int m = (1 + n) * n >> 1;
            if (m > k)// 超过了
            {
                temp = n - 1;
                m = (1 + temp) * temp >> 1;
                // 计算剩余金币
                sum += (k - m) * n;
            }
            else
            {
                temp = n;
            }
            // 计算总共金币
            sum += (temp * (temp + 1) * ((temp << 1) + 1) >> 1) / 3;
            return sum;
        }

两个方法测试如下:

C# 计算国王将金币作为工资,发放给忠诚的骑士_第2张图片

有个网友的代码也挺好,就是效率并不是很高,我们看看:

        static int CalculateGoldCoins3(int a)
        {
            int jin = 0;
            int X = 1;
            int t1 = 1;
            if (a < 1)
                return 0;
            for (int i = 1; i < a+1; i++)
            {
                jin += X;
                if (i == t1)
                {
                    X++;
                    t1 += X;
                }
            }
            return jin;
        }

纯暴力解决的,我们来测试看看

C# 计算国王将金币作为工资,发放给忠诚的骑士_第3张图片

效率是不是很差? 

你可能感兴趣的:(算法,c#,开发语言)