【问题标题】:Reversing a sub-array of an array , in less than O(n) time在少于 O(n) 的时间内反转数组的子数组
【发布时间】:2011-12-01 12:39:18
【问题描述】:

我们如何在少于 O(n) 的时间内反转数组(或任何其他数据结构,如链表(不是双重))的子数组(例如从第 i 个索引到第 j 个索引) ? O(n) 时间消耗是微不足道的。(我想在数组上多次执行此反转,例如从头开始并反转 n 次(每次,前进一个索引,然后再次反转它),所以应该有一种方法,它的摊销分析会给我们带来少于 O(n) 的时间消耗,知道吗?
提前谢谢:)

【问题讨论】:

  • 是的,但我没有要求代码,实际上我是通过 O(n) 完成的,出于好奇寻找更好的解决方案 :) 猜猜没关系,不是吗?
  • 是的,问没问题,但是家庭作业应该这样标记。
  • 通过所有这些逆转,您要达到的最终目标是什么?不要把我们放在一个“盒子”里,我们会有更好的机会进行一些开箱即用的思考;)
  • @Branko:这真的是一项漫长的任务,相信我,我所问的甚至根本不接近我必须做的:(我只是想改善我的期末考试的时间消耗算法,它使用这个任务(反向)来操作。
  • 找到了 O(1) 的解决方案,在 here 寻找我的答案

标签: arrays algorithm linked-list reverse


【解决方案1】:

我认为你想用错误的方法解决这个问题。我猜你想整体改进算法,而不是 O(n) 反转的东西。因为那是不可能的。如果你必须考虑 n 个元素中的每一个,你总是有 O(n)。

正如我所说,您可以做的是改进 O(n^2) 算法。你可以在 O(n) 中解决这个问题: 假设我们有这个列表:

a b c d e

然后您使用您的算法修改此列表:

e d c b a
e a b c d

等等..最后你有这个:

e a d b c

如果您有两个来自数组两端的指针并在指针之间交替(递增/递减/获取值),则可以获取此列表。这为您提供了整个过程的 O(n)。

这个算法更详细的解释:

使用前面的列表,我们希望元素按以下顺序排列:

a b c d e
2 4 5 3 1

所以你创建了两个指针。一个指向列表的开头,另一个指向末尾:

a b c d e
^       ^
p1      p2

那么算法的工作原理如下:

1. Take the value of p2
2. Take the value of p1
3. Move the pointer p2 one index back
4. Move the pointer p1 one index further
5. If they point to the same location, take the value of p1 and stop.
   or if p1 has passed p2 then stop.
   or else go to 1.

【讨论】:

  • :是的,改进 O(n^2) 算法是我所追求的,但是你能解释一下指针之间的交替是什么吗?谢谢
  • 哇,印象深刻 :) 这只是我试图得到的算法,谢谢你的帮助。
【解决方案2】:

对于给定的数组,您可以在 O(n) 时间内完成。这里l代表起始索引,r代表结束。所以我们需要将子数组从r反转到l。

public void reverse(int[] arr, int l, int r)
  {
      int d = (r-l+1)/2;
      for(int i=0;i<d;i++)
      {
         int t = arr[l+i];
         arr[l+i] = arr[r-i];
         arr[r-i] = t;
      }
    // print array here 
  }

【讨论】:

    【解决方案3】:

    正如 duedl0r 提到的,O(n) 是您的最小值。您必须将 n 个项目移动到新位置。

    既然你提到了一个链表,这里有一个 O(n) 的解决方案。

    如果您遍历所有节点并反转它们的方向,然后将末端连接到列表的其余部分,则子列表会反转。所以:

    1->2->3->4->5->6->7->8->9
    

    将 4 倒转到 7 会改变:

    4->5->6->7
    

    进入:

    4<-5<-6<-7
    

    然后让 3 指向 7,让 4 指向 8。

    为了保持一致性,稍微复制了 duedl0r 的格式:

     1. Move to the item before the first item to reorder(n steps)
     2. remember it as a (1 step)
     3. Move to the next item (1 step)
     4. Remember it as b (1 step)
    
    while not at the last item to reorder: (m times)
     5. Remember current item as c (1 step)
     6. Go to next item (1 step)
     7. Let the next item point to the previous item (1 step)
    
    having reached the last item to reorder:
     8. let item a point to item c (1 step)
    
    if there is a next item:
     9. move to next item (1 step)
     10. let item b point to current item (1 step)
    

    这是 O(n+1+1+1+m*(1+1+1)+1+1+1)。 没有Big O中不允许的所有数字,就是O(n+m),可以称为O(n+n),也可以称为O(2n)。

    这是 O(n)。

    【讨论】:

      猜你喜欢
      • 2012-05-08
      • 2017-01-26
      • 2020-01-28
      • 2019-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多