在最坏的情况下,计数的计算复杂度是否在ON * logN中进行?

问题描述

在纸牌游戏中,对表演过程中(游戏回合的一个阶段之一)的手掌跑动进行计数时,报告的上升子序列最长,该子序列仅包含增加1的值。如果存在重复值是该子序列的一部分,而没有报道过两次(或三倍,四倍等)。

一些例子:

(“ A”,“ 2”,“ 3”,“ 4”,“ 5”)=>(1,5)单次运行5

(“ A”,“ 2”,“ 3”,“ 4”,“ 4”)=>(2,4)重复运行4

(“ A”,“ 2”,“ 3”,“ 3”,“ 3”)=>(3,3)三连胜3

(“ A”,“ 2”,“ 3”,“ 4”,“ 6”)=>(1,4)单次运行4

(“ A”,“ 2”,“ 3”,“ 5”,“ 6”)=>(1,3)单次运行3

(“ A”,“ 2”,“ 4”,“ 5”,“ 7”)=>(0,0)没有运行

要处理出现的手大于纸牌手大小5的情况。如果运行具有子序列重复次数和子序列长度的最大乘积,则将选择该运行。

一些相关示例:

(“ A”,“ 2”,“ 2”,“ 3”,“ 5”,“ 6”,“ 7”,“ 8”,“ 9”,“ T”,“ J”)=> (1,7)单次运行7 (“ A”,“ 2”,“ 2”,“ 3”,“ 5”,“ 6”,“ 7”,“ 8”)=>(2,3)重复运行3

我寻找最大得分的方法如下:

  1. 创建等级列表并对其进行排序。 O(N * log(N))
  2. 创建一个列表以存储最大运行长度的长度以及存在的重复次数。初始化为[1个重复,1个长]。
  3. 创建与上述相同的列表以存储当前运行。
  4. 创建一个标志,该标志指示您遇到的重复项是否不是此值的初始重复项。将其初始化为False。
  5. 如果在初始重复项之后发现其他重复项值,则创建一个变量来存储重复项子序列中的增加。初始化为1。
  6. 迭代相邻元素之间的差异。 O(N)
  7. 如果差异大于1,则运行已结束。检查最大行程的元素乘积是否小于当前行程,并且当前行程的长度为3或更大。如果为真,则当前运行变为最大运行,并且当前运行列表重置为[1,1]。该标志被重置为False。重复子序列的增量重置为1。迭代到下一个值。
  8. 如果差为1,则将当前运行的长度增加1,并将标志设置为False。迭代到下一个值。
  9. 如果差异为0并且标志为False,则将重复子序列的增量设置为等于运行中当前的重复数。然后,将运行的重复次数加倍,并将标志设置为True。迭代到下一个
  10. 如果差异为0并且标记为True,则将运行次数增加重复子序列值的增加
  11. 迭代后,按照步骤7中的最大运行检查当前运行列表,并相应地设置最大运行。

我认为这具有O(N *(1 + log(N))。我认为这是最佳的时间复杂度,但是我不确定如何证明这一点或更好的算法是什么样的。无需先对列表进行排序就可以实现更好的时间复杂度的方法吗?如果没有,如何证明这是最佳时间复杂度?

重申两者之间的差异

解决方法

算法的时间复杂度是一条行之有效的路径。 证明算法的复杂度在数学家集群之间略有不同;相反,复杂性社区通常使用模块化伪代码和标准简化来工作。例如,基于输入长度的for循环为 O(N)(惊奇);排序列表的最佳方式是 O(log N)(通常)。要获得良好的治疗效果,请参见Big O,how do you calculate/approximate it?

请注意: O(N x(1 + log(N)))是一种草率的表示法,只有最大的复杂度因子(在N接近无穷大时占主导地位)删除1+ O(N log N)

正如我在评论中建议的那样,您可以简单地计算元素。保留一张计数列表,并根据您的卡值进行索引。在讨论算法时,请不要使用字符表示的“脏”数据:“ A23456789TJQK”;只需使用0-12或1-13的值即可。

for rank in hand:
    count[rank] += 1

这是对数据 O(N)的线性传递。

现在,遍历您的计数数组,找到最长的非零值序列。这是一个包含13个元素的固定长度列表,每个元素仅接触一次: O(1)。如果您累积了一个倍数(卡数)列表,那么最后还会有组合因素。

因此,生成的算法和代码为 O(N)


例如,让我们将其缩短为7个卡值,即0-6。给定输入整数

1 2 1 3 6 1 3 5 0

您已通过第一遍计算项目:

[1 3 1 2 0 1 1]

第二遍使您的最大运行长度为4,计数为[1 3 1 2]。

您报告的运行次数为4,三倍和两倍或得分计数

4 * (1 * 3 * 1 * 2)

您还可以计算对值:

2 * 3! + 2 * 2!