使用单个循环而不是 2 个 c++ 完成任务

Achieve a task using a single loop instead of 2 c++`

本文关键字:c++ 完成任务 单个 循环      更新时间:2023-10-16
这是一个

特定于任务的代码,我想知道是否有更好的方法。因此,喜欢逻辑和编码的人,请帮助我。

这是问题:

设 A 是 n 个正整数的数组。所有元素都是不同的。如果 A[i]> A[j] 并且 i

它非常简单明了。这是我实施的以下解决方案。逻辑部分。

         for(int j=0;j<nos.size();j++)
            {
                    for(int k=j+1;k<nos.size();k++)//always maintain condition that i<j and simply compare the numbers.
                    {
                            if(nos[j] > nos[k])
                            {
                                    spc++;//compute special pair.
                            }
                    }
            }

每个 nos[i] 都包含要为其计算特殊对的数组。有没有办法使用单个循环来做到这一点?或任何其他可以节省时间且速度更快的逻辑。提前感谢,我寻求从中了解更多信息。

您能否告诉我如何在不必执行代码的情况下确定哪个代码更快。非常欢迎您的意见。

主要问题是计算特殊对的数量。因此,只是spc的增量。

我认为@syam是正确的,这可以在 O(N log N( 时间(和 O(N( 额外空间(内完成。

您可以使用平衡二叉树来执行此操作,其中每个节点不仅有一个值,还具有其左侧子树中后代数的计数。

要计算特殊对,您需要从末尾到开头遍历数组,并将每个项目插入树中。当您在树中插入项目时,您会在其左侧子树中找到项目数 - 这些项目小于它,但在数组中位于其右侧(即,每个项目代表一个特殊对(。由于我们只通过 ~log(N( 节点下降来插入一个项目,因此计算左侧项目数的时间也是 O(log N(。我们还必须将左边的项目计数大约更新 log(N(/2 倍(再次,对数复杂度(。

这给了 O(N log N( 时间。

编辑以获取更多详细信息:树的平衡是相当传统的(例如,AVL 或 RB 树(,增加了在旋转时向左调整项目计数以恢复平衡。

插入每个项目时,您将在树中下降到要插入的点。在根节点上,您只需在左侧子树中记录项目计数。然后假设你的新项目大于这个,所以你下降到右边。执行此操作时,您正在做两件事:记录当前位置,以便知道此节点相对于已插入节点的位置,以及更新树中的计数,以便为以后的插入提供准确的计数。

因此,让我们通过一个小样本来工作。为了便于讨论,我们假设我们的输入是 [6, 12, 5, 9, 7]。因此,我们的第一个插入是 7,它成为我们树的根,没有后代,并且(显然(在其左侧为 0。

然后我们在其右侧插入 9。由于它在右边,我们不需要在下降过程中调整任何计数 - 我们只需将项目计数增加到左侧即可。就是这样,所以我们知道对于 9,我们有一个特殊的对([9,7],尽管我们没有跟踪它(。

然后我们插入 5。这是 7 的左侧,因此当我们从 7 下降时,我们将其左侧的项目数增加到 1。我们插入 5,左侧没有项目,因此它的计数为 0,并且没有特殊对。

然后我们插入 12。当我们点击根节点 (7( 时,它的左侧计数为 1 个项目。我们向右下降,因此我们再次递增根节点本身。然后我们再次从 9 向右下降,所以我们再添加一个(从其左侧子树 +0(,所以 12 有三个特殊对。

然后我们插入 6。我们从 7 向左下降,所以我们不从中添加任何东西。我们从 5 开始下降,所以我们加上 1(再次,从其左侧子树 +0(。所以它有一个特殊的对。

即使你需要生成所有特殊对(不仅仅是计算它们(,你也可以期望树在平均情况下提高速度(即,除了降序排序之外的几乎任何东西(。为了生成所有特殊对,我们像以前一样将每个项目插入树中,然后遍历该项目左侧的树。朴素算法遍历(并比较(数组中右侧的所有元素以找到那些将是特殊对的元素,这只需要遍历树即可找到那些实际上是特殊对的元素。

不过,这确实有一个副作用:它以不同的顺序生成对。不是按照数组中出现的顺序生成每个对,而是由第二个元素按降序生成这些对。例如,给定像 [4,1,2,3] 这样的输入,朴素算法将产生

[[4,1]、[4,2]、[4,3]],但这会产生 '[[4,3], [4,2], [4,1]]。

你的意思是你能比二次运行时做得更好吗?哈哈要看到这一点,请考虑递减序列A = (N, N - 1, ..., 2, 1)。对于这个序列,所有i < j (i, j)对都是特殊的,并且有O(N^2)这样的对。由于必须输出每个特殊对,因此需要二次时间才能执行此操作。

我认为你不能改进你的算法。在我看来,它显示了O(n²(的复杂性。您可以通过计算程序必须为长度为 n 的数组执行的内部循环数来证明这一点。第一个循环将有 n-1 次迭代,第二个循环 n-2,第三个循环 n-3 次,依此类推。使用前 n 个整数之和的公式进行总结(这次只是向后,不是从 1 到 n,而是从 2 到 n-1(:

(n-1)+(n-2)+(n-3)+...3+2 = n*(n-1)/2 - 1 .您不必循环访问最后一个剩余的元素,因为没有其他元素可以比较。实际上这是我看到的您的算法的唯一改进;-(:

for(int j=0;j<nos.size();j++)

for(int j=0;j<nos.size()-1;j++)

总结大 n 表达式 n*(n-1(/2 - 1 的行为类似于 n²,这就是我相信 O(n²( 的来源。如果我错了,请纠正我。