使用单个循环而不是2个c ++来实现任务

时间:2013-09-28 19:56:03

标签: c++ loops logic

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

这就是问题:

设A是n个正整数的数组。所有元素都是截然不同的。 如果A [i]> A [j]和i<然后,对(i,j)被称为一对特殊的A.给定n找到的数量 特殊的A对。

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

         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的增量。

3 个答案:

答案 0 :(得分:3)

我认为@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,它成为我们树的根,没有后代,并且(显然)在它的左边。

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

然后我们插入5.这是在7的左边,所以当我们从7下降时,我们将它的项目数增加到左边。我们插入5,左边没有项目,所以它得到一个数为0,没有特殊对。

然后我们插入12.当我们点击根节点(7)时,它在左边有一个项目。我们正在向右下降,所以我们再次为根节点本身增加。然后我们从9再次向右下降,所以我们再添加一个(左侧子树+0),所以12个有三个特殊对。

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

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

我认为你不能改进你的算法。在我看来,它显示了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²)来自的地方。如果我错了,请纠正我。