Linkedlist在恒定时间内跟踪min?

时间:2011-06-01 17:51:08

标签: algorithm language-agnostic linked-list

  

编辑:

     

这不是那么简单   您认为。考虑每个事实   添加一个新号码会推出一个   来自链表的旧号码。

     

解决方案似乎并非如此   跟踪一分钟很简单   带变量的数字。怎么样的呢?   最低限度被推出了   LinkedList的?那又怎样?你怎么知道的   新的分钟是什么?

我听到了这个采访问题:

您有固定长度的链表。

  • 在时间t = 0时,填充链表 随机数字。

  • 每次增加时,一个新的 数字被喂入了头部 链表,并推送一个数字 从尾巴出来。

  • 在第一个时间间隔之前,您只能进行一次遍历。

    • 这意味着一次遍历。 每次t。一次 。
  • O(1)存储。

您的任务是能够在每次交互时返回链表的最小值。

什么算法可以做到这一点?


有趣的提示:

由于没有关于时间复杂性的信息,您可以使用排序操作。唯一的问题是:排序需要多次迭代。

6 个答案:

答案 0 :(得分:9)

在有人误解我的帖子并向其投票之前澄清。

首先,

  

O(1)存储与单个寄存器不同。这意味着不断的空间使用。

第二,

  

我打算将你的LL称为恒定大小队列(CSQ)。

初始化队列时,还要初始化一个最小堆,其中队列的所有元素都保留对应于它们的堆节点的引用(指针)。

CS3 <1>操作
  • 在CSQ的O(1)时间内弹出1个元素。
  • O(lg n) time中的最小堆中删除相应的节点。
  • 将相应的元素添加到O(lg n) time中的最小堆。
  • 在O(1)时间内将1个元素推入CSQ,并标记对上面添加的堆节点的引用。

上述操作保证堆大小始终与队列大小保持同步 - 因此O(1)。我采用一个遍历限制意味着它必须比简单的O(n)搜索更优化。这是O(lg n)

寻找分钟

显然是O(1)。只需返回最小堆的头部。

答案 1 :(得分:0)

首先,LL通常用于动态尺寸。你可能想要一个固定大小的常规数组,因为通常它会占用更少的内存。

其次,你似乎有更多的队列而不是列表,这意味着你推送一个元素时弹出一个。在这种情况下,最小值可以不断变化。天真地,您可以在O(n)时间内搜索任何1D列表中的最小值。

不太天真地,您的LL也可以是预先排序的(插入排序)堆,在这种情况下,找到最小元素可以是O(1)(取决于所选择的结构)。但是,插入将花费O(n)时间。

我知道这不能回答你的问题,但这听起来像是一个家庭作业问题。使用此作为您的问题的指南/参考/帮助。 :)

希望一切都能得到解决,我希望我能帮助你!

答案 2 :(得分:0)

我很惊讶没有人发布这个(所以它可能是错的),但是(伪代码):

struct abc                                    // sorry for the name :)
{
    int pos
    int num
}
initialize
{
    struct abc min_array[linked_list_length];   // O(1) space

    fill(min_array, linked_list_elements);      // place every element in the array
    sort(min_array);                            // sort in ascending order, the sorting
                                                // compares num
}

insert_element
{
    linked_list.push(value);
    linked_list.pop();

    for each element in min_array {
        element.pos += 1

        if element.pos > linked_list.elementCount then   // this was popped out!
            element.pos = 1;
            element.num = value;
        end if
    }

    sort(min_array);        // as before, sorting compares only num
}

get_min_value
{
    return min_array[0];
}

答案 3 :(得分:0)

我唯一可能的解决方案是通过技术性:

由于链接列表的大小在WRITING时是固定的,这意味着N是常量。在这种情况下,我们在技术上允许存储辅助结构,该辅助结构是链表的直接副本(可能在数组中)。这是O(1)存储,因为N是常数。

答案 4 :(得分:0)

所以,基本上,这是一个队列,实现为链接列表(如果我错了,请纠正我)。 为了解决这个问题,我只想改变节点的想法。典型节点将具有下一个指针和值。将其更改为包含三个元素:nextPointer,value和minSoFar。如果你不喜欢改变队列设计的想法,那么,阅读这个算法,我最后提供了另一个想法。

我认为这可以在 O(1)中完成。技巧是遍历列表,跟踪列表中该点之前遇到的最小元素并将其存储在当前节点中。因此,例如,您有以下队列

前往 5 并在 13

处尾随

5 | 7 | 6 | 9 | 5 | 13 |

我修改的队列将包含

之类的节点

<强> {5,5} | {7,6} | {6,6} | {9,9-} | {13,13} | ({nodeVal,minSoFar})

现在,考虑一个操作,在队列中添加3并删除13,队列变为

<强> {3,3} | {5,5} | {7,6} | {6,6} | {9,9-} |

由于3小于当前头元素,因此头元素的最小值是其值

考虑另一种需要向队列添加15的情况

<强> {15,5} | {5,5} | {7,6} | {6,6} | {9,9-} |

由于15大于当前头元素,因此当前最小值变为5.

因此,要查找队列/列表中的最小元素,您需要做的就是检查head元素,您的时间复杂度将为O(1)

如果您不想修改队列,请维护并行队列并将minValueSoFar保留在该队列中并镜像该队列中的操作。

答案 5 :(得分:0)

如果可以如下定义节点,那么解决方案很简单:

class Node {
    int data;
    Node next;
    Node prevMin;
}