假设您正和朋友一起玩以下翻转游戏:给定一个仅包含这两个字符的字符串:namespace textMuc
{
public class Class1
{
private static int capdo = 100;
public int Muc
{
get { return capdo; }
set { capdo = value; }
}
}
}
和+
,您和您的朋友轮流连续翻转两个{{1进入-
。当一个人不能再采取行动时,游戏结束,因此另一个人将成为胜利者。
编写一个函数来确定首发球员是否可以保证获胜。
例如,给定s = "++"
,返回true。首发玩家可以通过将中间"--"
翻转为"++++"
来保证获胜。
这是我的代码:
"++"
它有效,但我不知道如何计算时间复杂度,因为函数会一直调用自己直到返回false。有人在这里分享一些想法吗?
同样在搜索过程中,我们会遇到重复计算,所以我想我可以使用hashmap来避免这些重复。 Key:String,Value:Boolean。
我使用hashmap更新的代码:
"+--+"
不过,我想知道如何分析这里的时间和空间复杂性?
答案 0 :(得分:2)
取n = arr.length - 1
首先通过n次递归调用。对于每个你已经删除了两个+,所以每个最多将有n-2个递归调用,依此类推。
所以你最多有n + n(n-2)+ n(n-2)(n-4)+ ......递归调用。
本质上这是n !!(1 + 1/2 + 1 /(2 * 4)+ 1 /(2 * 4 * 8)+ ...)因为1 + 1/2 + 1 /(2 * 4)+ 1 /(2 * 4 * 8)+ ...收敛,≤2,你有O(n !!)
关于内存,每个递归调用都有一个长度为n的数组,所以你有n + n n + n n n + n ...(n / 2次)... * n = n(n ^(n / 2)-1)/(n-1),这是O(n ^(n / 2))
这显然表明没有比详尽搜索更好的表现。
对于散列改进,您要求使用代码创建的所有可能组合。但是,你的代码与实际创建所有组合的代码差别不大,除了你用两个代替两个+的事实,这是通过某种因素而不是它的水平来降低复杂性。 。总的来说,最坏的情况与n / 2个位置中的比特组合的数量相同,即2 ^(n / 2)。观察到哈希函数本身可能有一些隐藏的日志,所以总复杂度将是搜索O(2 ^(n / 2)* ln(n / 2))和内存O(2 ^(n / 2))。
这是最糟糕的情况。但是,如果有安排让你无法获胜,那么当没有获胜策略时,上述内容实际上就是你需要依赖的复杂性。
平均情景的问题是你能够/不能获胜的案件数量及其在所有安排中的分配问题。这个问题与您的算法没什么关系,需要一套完全不同的工具才能解决。
经过一段时间检查上述推理是否正确无论如何,我对结果非常满意,因为它告诉我所有我需要知道的事情。你不能指望你会有一个有利的安排,我真的怀疑你只有0.01%的最坏情况安排,所以你需要准备最坏情况的情况,除非这是一些特殊的项目后面 - 信封计算是你的朋友。
无论如何,这些类型的计算是为了正确准备测试用例,而不是正确的最终实现。使用测试,你可以找到O()中隐藏的因素,考虑到编译器,内存消耗,分页等。
尽管如此,我们仍然不能保留这一点,当然,我们总能改进背后的推理。例如,实际上每个步骤都没有n-2,因为它取决于奇偶校验。例如+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ,甚至是n-4。所以半数的调用可能有n-3个递归调用,这些调用将是n / 2(n-3)+ n / 2(n-2)= n(n-5/2)
观察,因为n!= n !!(n-1)!!我们可以拿n !!≈√n!,再次n!= n !!!(n-1)!!!(n-2)!!!或者是!!!≈∛n!这可能导致我们应该得到类似O((n!)^(5/2))的结论。测试会告诉我在O((n!)^(x))中我们可以减少多少x = 3.
(在一个特定形式中寻找复杂性是很正常的,就像我们有O((n!)^(x))一样,尽管它可以用不同的方式表达。所以我会继续使用复杂形式O( (N!)^(X)),1≤x≤3)