C#无递归计数项目

时间:2018-07-16 09:52:09

标签: c# recursion

我需要解决一个测试问题,要求计算以X个苹果作为开始量,每次Y个苹果和{{ 1}}每次吃苹果都会添加一个苹果。

我当前的解决方案使用递归函数,因此如果1小于Y或给定的X很大,则会导致无限循环。

X

如何提高效率?可能有一种更优雅的方法来执行此操作,但我无法弄清楚。

编辑: 原始测试问题文本:

public class Apples
{
    // Counts iterations. If we eat less than we add new every, it'll loop infinetely!
    private static int _recursions;

    private static int _applesRemaining;
    private static int _applesEaten;


    public static int CountApples(int startingAmount, int newEvery)
    {
        if (newEvery > startingAmount) newEvery = startingAmount;
        Console.WriteLine("startingAmount: " + startingAmount + ", newEvery: " + newEvery);

        _applesRemaining = startingAmount;

        /* Eat 'newEvery' amount */
        _applesRemaining -= newEvery;
        _applesEaten += newEvery;

        Console.WriteLine("Eat: " + newEvery + ", remaining: " + _applesRemaining);

        /* Get one additional candy */
        _applesRemaining += 1;
        Console.WriteLine("Added 1.");

        if (_applesRemaining > 1 && _recursions++ < 1000)
        {
            CountApples(_applesRemaining, newEvery);
        }
        else
        {
            if (_recursions > 1000) Console.WriteLine("ABORTED!");

            /* Eat the one we've just added last. */
            _applesEaten += 1;
        }

        return _applesEaten;
    }


    public static void Main(string[] args)
    {
        Console.WriteLine(CountApples(10, 2) + "\n");
    }
}

5 个答案:

答案 0 :(得分:2)

递归解决这个问题似乎有点过分,所以我建议使用另一种数学方法。

让我们从一个事实开始,即我们总是至少要吃X个苹果。真正的问题是,在吃完所有东西后,总共要添加多少苹果。

假设ni是我“进食”后剩余的苹果数。然后:

n0 = X
n1 = X - Y + 1
n2 = X - 2Y + 2
...
ni = X - i(Y - 1)

求解ni = 0将使我们得到i-吃所有东西所需的“进食”次数:

ni = 0 = X - i(Y - 1) => i = X / (Y - 1)

现在我们知道我们要吃多少次,所以要吃的苹果总数是原始X加上Y个苹果被食用的次数(因为每次做时我们都会得到一个额外的苹果)这样):

tot = X + roundDown(i) = X * roundDown(X / (Y - 1))

我们将结果四舍五入,因为设置ni = 0会捕获部分“进食”,然后导致部分苹果。

示例:

X = 7, Y = 3 => tot = 7 + roundDown(7 / (3 - 1)) = 7 + roundDown(3.5) = 10
starting with 7:
0 eaten, 7 remain
3 eaten, 1 gained, 5 remain
3 eaten, 1 gained, 3 remain
3 eaten, 1 gained, 1 remains
1 eaten, nothing gained, nothing remains
--
10 eaten in total

答案 1 :(得分:2)

如果您只想计算吃的苹果而不跟踪进度,则无需递归也不需要循环。您可以使用线性O(1)代码简单地计算结果:

int result = apples + apples / (eatenPerRound - 1);
if ((apples % (eatenPerRound - 1)) <= 1) {
    result--;
}
Console.WriteLine($"Total number of {result} apples eaten.");

答案 2 :(得分:2)

不确定答案是否受限制,但是通过一些数学运算,您可以想到以下方法:

public int CheatEatenApples(int startingApples, int newEvery)
{
    var firstGuess = (double)startingApples*newEvery/(newEvery-1);

    if (firstGuess%1==0) // Checks if firstGuess is a whole number
    {
        return (int)firstGuess-1;
    }
    else
    {
        return (int)firstGuess;
    }
}

使用我们不断获取新苹果这一事实来计算第一个猜测,因此,我们每食用newEvery个苹果,就可以免费食用其中一个!当然,如果第一个猜测是整数,这实际上会分解。这将需要提供免费的苹果才能让我们吃它。令人困惑的是,让我们看一个例子。

如果我们有3个苹果,并且每2个苹果得到一个新苹果,那么我们的第一个猜测就是6个苹果。但是那是三个免费的苹果,我们只吃了三个免费的六个苹果就得到了第三个!因此,在这种情况下,我们需要起飞。剩下的时间,我们可以四舍五入以除去小数部分,该小数部分代表我们与免费苹果的距离。

这只是表明您在学校学习的数学可以在现实世界中使用。上面是一些简单的计算,可能会比大多数迭代/递归方法更快。

附加说明:在现在删除的注释中指出,使用整数算法进行firstGuess计算可能会更好。这样可以省去将返回值返回给int的需要。它之所以被编写为当前状态,部分是因为这是我在编写它时所考虑的方式,部分是因为在迭代正确的答案时,我在调试时查看了小数部分(以确认只有在firstGuess完全需要做一些特别的事情。

如果确实改为整数数学,则需要更改if条件(因为它不再按原样工作),然后您将得到Sefe的答案。

最终通知

如果您确实想进行迭代技术,那么以下方法将符合规范:

public int CalculateEatenApples(int startingApples, int newEvery)
{
    int applesEaten = 0;
    int apples = startingApples;
    while (apples>0)
    {
        applesEaten++;
        apples--;
        if (applesEaten%newEvery==0)
        {
            apples++;
        }
    }
    return applesEaten;
}

非常简单。当您有苹果时,它会增加您食用的数量并减少您剩下的数量。然后,如果您吃的数字是newEvery的倍数,那么它会增加一个数字。

答案 3 :(得分:1)

这是我如何理解您的问题的一个运行示例:

using System.IO;
using System;

class Program
{
    static void Main()
    {
        Console.WriteLine(GetNumberOfApplesEaten(100,5));
    }

    public static int GetNumberOfApplesEaten(int X, int Y)
    {
        int result = 0;

        // while we can eat 'Y' apples
        while(X >= Y)
        {
            // we eat & count those apples
            result += Y;
            X -= Y;
            // we add an extra apple
            X++;
        }
        // we eat what's left
        result += X;

        return result;
    }
}

编辑

我将X > Y更改为X >= Y,以使其符合您的规格。

检查javascript等效项:

function getNumberOfApplesEaten(X,Y) {
    var result = 0;

    // while we can eat 'Y' apples
    while(X >= Y) {
        // we eat & count those apples
        result += Y;
        X -= Y;
        // we add an extra apple
        X++;
    }
    // we eat what's left
    result += X;

    return result;
}

console.log(getNumberOfApplesEaten(3,2))

答案 4 :(得分:0)

我手头没有C#工具链,因此下面的示例在Python中社区编辑制作了C#示例!魔术!

如评论中所述,这是一个迭代问题,而不是递归问题。

var apples = 100;
var eaten = 0;
var eatPerRound = 5;
var gainPerRound = 1;

while(apples > 0)
{
    apples -= eatPerRound;
    eaten += eatPerRound;
    apples += gainPerRound;
    Console.WriteLine($"Round {round}: {eaten} apples eaten, {apples} left");
}

Round 1: 5 apples eaten, 96 left
Round 2: 10 apples eaten, 92 left
Round 3: 15 apples eaten, 88 left
Round 4: 20 apples eaten, 84 left
Round 5: 25 apples eaten, 80 left
Round 6: 30 apples eaten, 76 left
Round 7: 35 apples eaten, 72 left
Round 8: 40 apples eaten, 68 left
Round 9: 45 apples eaten, 64 left
Round 10: 50 apples eaten, 60 left
Round 11: 55 apples eaten, 56 left
Round 12: 60 apples eaten, 52 left
Round 13: 65 apples eaten, 48 left
Round 14: 70 apples eaten, 44 left
Round 15: 75 apples eaten, 40 left
Round 16: 80 apples eaten, 36 left
Round 17: 85 apples eaten, 32 left
Round 18: 90 apples eaten, 28 left
Round 19: 95 apples eaten, 24 left
Round 20: 100 apples eaten, 20 left
Round 21: 105 apples eaten, 16 left
Round 22: 110 apples eaten, 12 left
Round 23: 115 apples eaten, 8 left
Round 24: 120 apples eaten, 4 left
Round 25: 125 apples eaten, 0 left