【问题标题】:Is there a way to reduce the time complexity of the program?有没有办法降低程序的时间复杂度?
【发布时间】:2019-09-01 06:25:13
【问题描述】:

假设有 n 个囚犯围成一圈站着。第一个犯人有一把刀,他用刀杀死了第二个犯人,然后把刀传给了第三个人,第三个人杀死了第四个犯人,然后把刀传给了第五个犯人。

重复这个循环,直到只剩下一个囚犯。请注意,囚犯们站成一圈,因此第一个囚犯在第 n 个囚犯旁边。返回最后一个囚犯的索引。

我尝试使用循环链表来实现该解决方案。这是我的代码

循环链表的结构是:-

struct Node
{
    int Data;
    Node *Next;
};
Node *Head = NULL;

这是我的 deleteByAddress() 和 main() 函数:-

inline void deleteByAddress(Node *delNode)
{
Node *n = Head;
if(Head == delNode)
{
    while(n -> Next != Head)
    {
        n = n -> Next;
    }
    n -> Next = Head -> Next;
    free(Head);
    Head = n -> Next;
    return ;
}

while(n -> Next != delNode)
{
    n = n -> Next;
}
n -> Next = delNode -> Next;
delete delNode;
}

int main(void)
{
for(int i = 1 ; i <= 100 ; i++)
  insertAtEnd(i);

Node *n = Head;
while(Head -> Next != Head)
{
    deleteByAddress(n -> Next);
    n = n -> Next;
}
cout << Head -> Data;
return 0;
}

上面的代码完美运行,并在 n = 100 时产生所需的输出,即 73。

有什么方法可以降低时间复杂度或使用更高效的数据结构来实现相同的问题。

【问题讨论】:

  • 应用一致的缩进方案会帮助你自己和那些试图帮助你的人。 (我认为它实际上可能是一致的,但非常令人困惑的不寻常。请为每个 { 缩进并为每个 } 取消缩进,而不仅仅是那些内部函数。)
  • 双链表?
  • Head 在您显示的代码中似乎未定义。请升级到minimal reproducible example
  • 减少时间复杂度的方法是,在大多数情况下,挑战因超时原因而失败,而不是模拟和使用数学。幸运的是,它变成了单行。考虑索引并尝试确定如何找到那些在第一轮中幸存下来的索引。然后考虑第二轮。刀是怎么来的?这取决于什么?例如,对于 2 的幂,最后一个常设囚犯将始终是索引为 0 的那个。
  • 感谢您展示Head 的声明、定义和初始化。但是请一路制作minimal reproducible example

标签: c++ algorithm linked-list


【解决方案1】:

这被称为Josephus problem。正如维基百科页面显示和其他人指出的那样,当k 为 2 时,有一个公式。一般的重复是

// zero-based Josephus
function g(n, k){
  if (n == 1)
    return 0
  
  return (g(n - 1, k) + k) % n
}

console.log(g(100, 2) + 1)

【讨论】:

    【解决方案2】:

    这可以通过O(1) 复杂性轻松解决,使用以下方法:

    last = (num - pow(2, int(log(num)/log(2)))) * 2 + 1
    

    例如num = 100:

    last = (100 - pow(2, int(log(100)/log(2)))) * 2 + 1 = 73
    

    如果你有log2() 函数,你可以替换一个有点丑的log(num)/log(2),它基本上取以2 为底的对数。

    【讨论】:

      【解决方案3】:

      使用 1 个循环。您可以在每次迭代时抓取当前的下一个,然后将当前设置为下一个,然后删除下一个。

      这假设所有数据都是事先设置好的,并且在您达到界限时忽略下一个变量的重写。

      【讨论】:

        【解决方案4】:

        降低时间复杂度的诀窍是想出比通过模拟强制执行更聪明的算法。

        在这里,像往常一样,关键显然是解决数学问题。例如,第一个循环用i%2=1 杀死每个人(假设基于0 的索引),第二个用i%4=(n+1)%2*2 左右的人等等 - 我正在寻找一个封闭的形式来直接计算幸存者。它可能会归结为一些位操作,从而产生一个 O(log n) 算法,该算法在实践中几乎是即时的,因为所有算法都完全在 CPU 寄存器中运行,甚至没有 L1 缓存访问。

        【讨论】:

          【解决方案5】:

          对于这样一个简单的处理,列表操作和内存分配将主导计算,你可以只使用一个数组,其中你有一个指向第一个存活的索引,每个元素都是下一个存活的索引。

          也就是说你确实可以搜索一个避免循环的公式......例如,如果囚犯的数量是偶数,那么在第一个“循环”之后你最终会得到一半的囚犯和刀回到第一个的手。这意味着n为偶数时幸存囚犯的索引是

          f(n) = 2 * f(n / 2)   # when n is even
          

          如果n 很奇怪,事情会稍微复杂一些...在第一个循环之后,您将得到(n + 1)/2 囚犯,但最后一个人手中的刀,所以需要一些模运算,因为您需要“调整”递归调用f((n + 1)/2)的结果。

          【讨论】:

            【解决方案6】:

            减少时间复杂度的方法是,在大多数情况下,挑战因超时原因而失败,而不是模拟和使用数学。运气好的话,它会变成单线。

            算法可以加速很多,如果你改为:

            请注意,如果囚犯总数是 2 的幂,则索引 0 将始终存在。

            对于其他情况:

            • 确定小于或等于囚犯人数的二的最高幂
            • 确定 R,将囚犯人数减少到 2 的幂时的其余部分
            • 最后活下来的囚犯将是在杀了这么多囚犯后得到刀的人

            试图找出是哪个囚犯。

            5 名囚犯的情况(1 高于 22,R=1):

                     01234 
            Deaths 1: x x
            Deaths 2:x   x
            last    :  O
            

            6 例(R=2):

                     012345
            Deaths 1: x x x 
            Deaths 2:x x      (index 4 kills index 0 after index 2 was killed by index 0)
            last    :    O
            

            7 例(R=3):

                     0123456
            Deaths 1:xx x x   (index 6 kills index 0 after index 5 was killed by index 2)
            Deaths 2:  x x    (index 6 kills index 2 after index 4 was killed by index 2)
            last    :      O
            
            

            8 的情况是 2 的下一个幂,索引 0 仍然存在。

            最后,最后的幸存者总是索引为 2*R 的那个。
            因此,您只需确定 R,而不是进行模拟。
            这在最坏的情况下应该是可能的,其时间复杂度是对数以 2 为底的总数。

            【讨论】:

              猜你喜欢
              • 2020-09-15
              • 1970-01-01
              • 2016-01-08
              • 2015-12-01
              • 2011-06-15
              • 2022-08-24
              • 1970-01-01
              • 1970-01-01
              • 2014-04-21
              相关资源
              最近更新 更多