我需要解决一个测试问题,要求计算以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");
}
}
答案 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