没有递归的 C# 计数项目
Posted
技术标签:
【中文标题】没有递归的 C# 计数项目【英文标题】:C# Counting Items Without Recursion 【发布时间】:2018-12-23 20:06:44 【问题描述】:我需要解决一个测试问题,询问总共可以吃多少个苹果每次吃苹果。
我当前的解决方案使用递归函数,因此如果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");
如何提高效率?可能有一种更优雅的方法可以做到这一点,但我想不通。
编辑: 原试题文字:
/**
* You are given startingAmount of Apples. Whenever you eat a certain number of
* apples (newEvery), you get an additional apple.
*
* What is the maximum number of apples you can eat?
*
* For example, if startingAmount equals 3 and newEvery equals 2, you can eat 5 apples in total:
*
* Eat 2. Get 1. Remaining 2.
* Eat 2. Get 1. Remaining 1.
* Eat 1.
*/
【问题讨论】:
Y 个苹果每次都在吃。你能解释一下吗?知道苹果在吃东西很有趣。你的意思是吃了吗? 这听起来像是简化成一个线性方程,但无论哪种方式都不需要使用递归。 @david 这是一个错字。已更正。 一开始是3个苹果,每次吃掉5个苹果会怎样? 看到您的更新后,我想澄清一下:不是每次都吃苹果。一次吃一个苹果,每次你达到 Y 的倍数时,你就多吃一个苹果。这在其规范中是绝对明确的。 【参考方案1】:不确定你的答案是否受到限制,但通过一些数学计算,你可以想出以下方法:
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 个苹果并且每两个得到一个新苹果,那么我们的第一个猜测是 6 个苹果。然而,那是三个免费的苹果,我们在吃完 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
的倍数,那么它就会增加一个。
【讨论】:
我不知道你可以做 double%1 来做那个检查。不错。 @MineR:我不是 100% 确定进行检查的最佳方法,因此在 ***.com/questions/2751593/… 中找到了建议 @PaulF:我认为你可能是对的。上面的方法被写成结合了我在脑海中的想法,因为在迭代和测试时,我正在查看它的小数部分。我要让它保持原样。部分原因是更改为整数算术意味着更改我的 if 条件以及我必须将其更改为的内容将使其与 Sefe 的答案基本相同。 :) 至少现在有两个略有不同的版本可供选择。 :) 我确实看到了 if 语句的细微差别,并删除了我的评论。 @PaulF:我认为这绝对是一个很好的评论,值得保留,因为现在你已经删除了它,我会在我的答案中添加一个注释。 :)【参考方案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
【讨论】:
【参考方案3】:如果您只想计算吃掉的苹果而不跟踪进度,则不需要递归和循环。您可以使用线性 O(1) 代码简单地计算结果:
int result = apples + apples / (eatenPerRound - 1);
if ((apples % (eatenPerRound - 1)) <= 1)
result--;
Console.WriteLine($"Total number of result apples eaten.");
【讨论】:
我对这种方法持怀疑态度 @Rafalon 怀疑结果是否正确回答了问题?问题是“你最多可以吃多少个苹果?”。这个问题已经回答了。 请注意,这并没有给出他需要 3 开始,每轮吃 2 的结果...应该给出 5,但给出 6。 如果您可以对其进行更改以使其正常工作,那么它应该被评为最快。 :) @Sefe MineR 的评论正是我对这种方法持怀疑态度的原因【参考方案4】:这是我如何理解您的问题的运行示例:
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))
【讨论】:
这对我有用,非常感谢!我添加了一个检查,以防 Y 为 1,这将导致无限循环。 @BadmintonCat 是的,你一定要检查X > 0
和 Y > 1
【参考方案5】:
我手头没有 C# 工具链,所以下面的示例是用 Python 编写的 社区编辑制作了 C# 示例!魔法!
正如 cmets 中所说,这是一个迭代问题,而不是递归问题。
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
【讨论】:
This是我经常使用的在线C#编译器 这并不完全加起来。假设 X 为 3,Y 为 2,它应该得到 5(吃 2,加 1,吃 2,加 1,吃 1),但是这段代码返回 6。 @BadmintonCat 你有 3 个,你去吃饭,现在你有 4 个,你吃了 2 个,还剩 2 个,你去吃饭,你有 3 个,你吃 2 个,还剩 1 个,你去吃有2个,你吃完还有0个。总共是 6 个。 @BadmintonCat 添加额外苹果的顺序很重要。 @MineR 好的,但这不是测试问题给出示例的方式(它与我之前的评论一样)。以上是关于没有递归的 C# 计数项目的主要内容,如果未能解决你的问题,请参考以下文章