使用单个循环而不是 2 个 c++ 完成任务
Achieve a task using a single loop instead of 2 c++`
特定于任务的代码,我想知道是否有更好的方法。因此,喜欢逻辑和编码的人,请帮助我。
这是问题:
设 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] 这样的输入,朴素算法将产生
你的意思是你能比二次运行时做得更好吗?哈哈要看到这一点,请考虑递减序列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²( 的来源。如果我错了,请纠正我。
- C++一个线程如何正确通信其任务已完成?
- Qt异步调用:如何在异步调用完成任务后运行一些东西
- 完成搜索任务时为空输出文件
- 如何检查io_service中的任务是否已完成
- 等待任何任务完成
- 在隐式屏障处等待 OpenMP 任务完成
- 产量提升::asio::协同作业,直到任务完成
- 任务 ":app:ndkBuild" 执行失败。>进程'Command'完成,退出值为非零 2
- 如何处理任务,同时剩余的线程完成工作
- SQLite是否可以完成此任务?存储路径名与文件属性
- QThreadPool 的问题:无法完成所有任务
- 如何仅在使用 c++ 中的 boost 完成所有任务时才向线程池添加新任务
- 在 c++ 中使用函数或类来完成简单的任务
- 发出std::async任务完成的信号
- 在线程在 C++ 中完成后将新任务分配给线程
- 正在将unique_lock用于可以通过lock_guard较慢完成的任务
- 父级不等待工作线程完成任务
- 使用单个循环而不是 2 个 c++ 完成任务
- C++11通过两种算法中的一种来完成任务
- C++-如何在程序终止后完成一些任务