【问题标题】:Custom Data Structure for push, pop and finding minimum用于推送、弹出和查找最小值的自定义数据结构
【发布时间】:2011-08-31 11:46:12
【问题描述】:

我刚刚被问到A公司的面试问题如下:

问题: 设计一个数据结构,其中有 3 个操作,push、pop 和找到最小值。您应该在恒定时间内完成所有 3 项操作。

我的答案我会使用一个链表,我可以在恒定时间内进行插入和删除,我会使用额外的内存来存储最小值。

他提出了第二个问题,如果你弹出最小值,你如何找到第二个最小值?再次,在恒定时间内。

你会告诉他什么?

【问题讨论】:

标签: algorithm data-structures


【解决方案1】:

这是实现上述 Bryce Siedschlaw 给出的算法的 C 代码:

#include<stdio.h>
#include<stdlib.h>

#define minimumOf(a,b) (a<b) ? a : b;

struct node{
    int data;
    struct node* next;
    int min;
};

void push(struct node **head_ref, int new_data){
    struct node* new_node = (struct node *)malloc(sizeof(struct node));
    new_node->data = new_data;

    if(*head_ref == NULL)
        new_node->min = new_data;
    else
        new_node->min = minimumOf(new_data,(*head_ref)->min);

    new_node->next = *head_ref;
    *head_ref = new_node;
}

int minimum(struct node *head){
    return head->min;
}

int pop(struct node **head_ref){
    int pop_data = (*head_ref)->data;
    (*head_ref) = (*head_ref)->next;
    return pop_data;
}

void printList(node *head){
    while(head != NULL){
        printf("%d->", head->data);
        head = head->next;
    }
    printf("\b\n");
}

int main(){
    struct node* a = NULL;

    push(&a, 100);
    push(&a, 24);
    push(&a, 16);
    push(&a, 19);
    push(&a, 50);
    printList(a);
    printf("Minimum is:%d\n", minimum(a));
    printf("Popped:%d\n",pop(&a));
    printf("Minimum is:%d\n", minimum(a));
    printf("Popped:%d\n",pop(&a));
    printf("Minimum is:%d\n", minimum(a));
    printf("Popped:%d\n",pop(&a));
    printf("Minimum is:%d\n", minimum(a));
    printf("Popped:%d\n",pop(&a));
    printf("Minimum is:%d\n", minimum(a));
}

【讨论】:

    【解决方案2】:
    【解决方案3】:

    最小堆栈问题 - http://courses.csail.mit.edu/iap/interview/Hacking_a_Google_Interview_Practice_Questions_Person_A.pdf

    来自 PDF:

    问题:最小筹码量

    描述一个支持“push”、“pop”和“find minimum”的栈数据结构 操作。 “查找最小值”返回堆栈中的最小元素。

    很好的答案:存储两个堆栈,其中一个包含堆栈中的所有项目 其中一个是一堆最小值。要推送一个元素,请将其推送到第一个 堆。检查是否小于第二个栈顶的item;如果是这样,推 它放到第二个堆栈上。要弹出一个项目,从第一个堆栈中弹出它。如果是顶 第二个堆栈的元素,从第二个堆栈中弹出它。找到最小值 元素,只需返回第二个堆栈顶部的元素。每次操作 需要 O(1) 时间。

    【讨论】:

    • 这假设没有重复,但调整它以允许它们意味着只需用“更小或等于”替换“更小”。
    • @Jim Mischel:如果是这样,那么您不必担心,因为您必须先删除 4 和 3,然后才能摆脱 1。这意味着最小堆栈将包含列表中的最小值
    • 您是否阅读了 pdf 中的问题?它没有说恒定时间,您可以使用列表或使用最小堆以线性时间来完成,您甚至可以在 logn 中完成
    • 是的,我做到了。该问题要求您构建一个包含操作 push、pop 和 find min 的数据结构。他们的解决方案在恒定时间内完成所有三个操作。
    【解决方案4】:

    让每个节点保留对先前最小项的另一个引用。因此,当您弹出最小的项目时,您可以恢复以前最小的项目。因为你只能 push 和 pop 它将是正确的节点。

    【讨论】:

    • 我想你和我说的是同一件事,是吗?
    【解决方案5】:

    如果你像你说的那样做一个链表,但也存储当前的最小值。添加新数字时,它会查看前一个最小值,如果当前值较低,则将当前最小值更改为当前值。

    例如...假设您有数据:3、6、4、2、7、1。那么这就是列表的样子

    值|最小值

    3|3 -> 6|3 -> 4|3 -> 2|2 -> 7|2 -> 1|1

    这将在您添加/删除项目时跟踪分钟。

    编辑: 我提到倒退,它会是这样的: 1|1 -> 7|2 -> 2|2 -> 4|3 -> 6|3 -> 3|3 那么你就不需要“页脚”了。

    【讨论】:

    • 授予您需要有一个根节点和一个指定为“页脚”的节点,以便您可以在 O(1) 中访问末尾
    • 或者你可以倒退并在前面添加东西并在每次插入时更改根节点......这也可以
    • 但是如果你删除1,你必须更新列表中的所有元素,所以你的pop操作不是恒定的
    • 但是你不能只“更新” 2...你只能插入和弹出。除非我理解错了
    • @Bryce Siedschlaw 你是对的,但在这种情况下,你存储的数量不再是最小值,对吧?
    猜你喜欢
    • 1970-01-01
    • 2012-12-23
    • 2021-11-10
    • 2013-07-23
    • 2018-01-08
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    相关资源
    最近更新 更多