在O(1)时间内检索堆栈中的Min元素

时间:2012-11-04 22:26:00

标签: performance algorithm data-structures stack

我问这个问题的原因是因为我无法理解为什么我认为不能应用于这个特定问题的方式

“你会如何设计一个堆栈, 除了push和pop之外,还有一个函数min返回最小元素?推,弹和分钟都应该在O(1)时间内运行

我的基本解决方案:如果我们在 stack 类中有一个变量,那么每当我们将一个项目推送到堆栈时,我们会检查它是否可行是比我们的 min 变量。如果它将值赋给min,如果不是忽略。

你仍然可以获得最小函数的O(1);

int getMinimum(){
  return min;
}

为什么永远不会提到这个解决方案,或者我的想法是什么错误?

4 个答案:

答案 0 :(得分:24)

如果您从堆栈中弹出数字,这将无效。

实施例。 2,4,5,3,1。弹出1后,你的最低要求是什么?

解决方案是保持一堆最小值,而不仅仅是一个值。如果遇到的值小于当前最小值,则需要将其推入最小堆栈。

实施例

Push(4):
Stack: 4
Min-stack: 4

Push(2):
Stack: 4 2
Min-stack: 4 2

Push(2):
Stack: 4 2 2
Min-stack: 4 2 2

Push(5):
Stack: 4 2 2 5
Min-stack: 4 2 2

Push(3):
Stack: 4 2 2 5 3
Min-stack: 4 2 2

Push(1):
Stack: 4 2 2 5 3 1
Min-stack: 4 2 2 1

Pop():
Stack: 4 2 2 5 3
Min-stack: 4 2 2

Pop():
Stack: 4 2 2 5
Min-stack: 4 2 2

Pop():
Stack: 4 2 2
Min-stack: 4 2 2

Pop():
Stack: 4 2
Min-stack: 4 2

Pop():
Stack: 4
Min-stack: 4

答案 1 :(得分:1)

使用链接列表跟踪将成为头部的最小值。

请注意,linkedlist.app = append(我们将值放在尾部)。 linkedlist.pre = prepend(我们将值作为链表的头部)

public class Stack {

** LOAD CSV WITH HEADERS FROM "file:///C:/coursera/data/test.csv" AS line
MERGE (n:MyNode {Name:line.Source})
MERGE (m:MyNode {Name:line.Target})
MERGE (n) -[:TO {dist:line.distance}]-> (m)**

}

答案 2 :(得分:0)

我找到了这个解决方案here

struct StackGetMin {
  void push(int x) {
    elements.push(x);
    if (minStack.empty() || x <= minStack.top())
      minStack.push(x);
  }
  bool pop() {
    if (elements.empty()) return false;
    if (elements.top() == minStack.top())
      minStack.pop();
    elements.pop();
    return true;
  }
  bool getMin(int &min) {
    if (minStack.empty()) {
      return false;
    } else {
      min = minStack.top();
      return true;
    }
  }
  stack<int> elements;
  stack<int> minStack;
};

答案 3 :(得分:0)

我们定义一个变量minEle,用于存储堆栈中的当前最小元素。现在有趣的部分是,如何处理删除最小元素的情况。为了处理这个问题,我们将“2x-minEle”推入堆栈而不是x,以便可以使用当前minEle检索先前的最小元素,并将其值存储在堆栈中。以下是工作的详细步骤和说明。

推(x):在堆栈顶部插入x

If stack is empty, insert x into the stack and make minEle equal to x.
If stack is not empty, compare x with minEle. Two cases arise:
    If x is greater than or equal to minEle, simply insert x.
    If x is less than minEle, insert (2*x – minEle) into the stack 
    and make minEle equal to x.
    For example, let previous minEle was 3.
    Now we want to insert 2. We update minEle as 2 and insert 2*2 – 3 = 1 into the stack.

Pop():从堆栈顶部删除元素。

Remove element from top. Let the removed element be y. Two cases arise:
    If y is greater than or equal to minEle,
    the minimum element in the stack is still minEle.
    If y is less than minEle, the minimum element now becomes 
    (2*minEle – y), so update (minEle = 2*minEle – y). 
    This is where we retrieve previous minimum from current minimum 
    and its  value in stack. For example, let the element to be 
    removed be  1 and minEle be 2. We remove 1 and update minEle as 2*2 – 1 = 3.





 / Java program to implement a stack that supports
 // getMinimum() in O(1) time and O(1) extra space.
 import java.util.*;

  // A user defined stack that supports getMin() in
  // addition to push() and pop()
class MyStack
{
Stack<Integer> s;
Integer minEle;

// Constructor
MyStack() { s = new Stack<Integer>(); }

// Prints minimum element of MyStack
void getMin()
{
    // Get the minimum number in the entire stack
    if (s.isEmpty())
        System.out.println("Stack is empty");

    // variable minEle stores the minimum element
    // in the stack.
    else
        System.out.println("Minimum Element in the " +
                           " stack is: " + minEle);
}

// prints top element of MyStack
void peek()
{
    if (s.isEmpty())
    {
        System.out.println("Stack is empty ");
        return;
    }

    Integer t = s.peek(); // Top element.

    System.out.print("Top Most Element is: ");

    // If t < minEle means minEle stores
    // value of t.
    if (t < minEle)
        System.out.println(minEle);
    else
        System.out.println(t);
}

// Removes the top element from MyStack
void pop()
{
    if (s.isEmpty())
    {
        System.out.println("Stack is empty");
        return;
    }

    System.out.print("Top Most Element Removed: ");
    Integer t = s.pop();

    // Minimum will change as the minimum element
    // of the stack is being removed.
    if (t < minEle)
    {
        System.out.println(minEle);
        minEle = 2*minEle - t;
    }

    else
        System.out.println(t);
}

// Insert new number into MyStack
void push(Integer x)
{
    if (s.isEmpty())
    {
        minEle = x;
        s.push(x);
        System.out.println("Number Inserted: " + x);
        return;
    }

    // If new number is less than original minEle
    if (x < minEle)
    {
        s.push(2*x - minEle);
        minEle = x;
    }

    else
        s.push(x);

    System.out.println("Number Inserted: " + x);
}
 };

 // Driver Code
 public class Main
{
public static void main(String[] args)
{
    MyStack s = new MyStack();
    s.push(3);
    s.push(5);
    s.getMin();
    s.push(2);
    s.push(1);
    s.getMin();
    s.pop();
    s.getMin();
    s.pop();
    s.peek();
}
 }

这种方法有何用处?

当要插入的元素小于minEle时,我们插入“2x - minEle”。 需要注意的重要一点是,2x - minEle将始终小于x(在下面证明),即新的minEle,当弹出这个元素时,我们会看到由于弹出元素小于minEle而发生了一些不寻常的事情。所以我们将更新minEle

push()中2 * x - minEle如何小于x?

x&lt; minEle表示x - minEle&lt; 0

//在两边添加x

x - minEle + x&lt; 0 + x

2 * x - minEle&lt; x

我们可以得出结论2 * x - minEle&lt;新的minEle

当弹出时,如果我们发现元素(y)小于当前的minEle,我们发现新的minEle = 2 * minEle - y。

之前的最小元素prevMinEle是2 * minEle - y?

pop()中的

是弹出元素吗?

//我们将y推到2倍 - prevMinEle。这里

// prevMinEle是插入y之前的minEle

y = 2 * x - prevMinEle

//使minEle的值等于x  minEle = x。

new minEle = 2 * minEle - y

        = 2*x - (2*x - prevMinEle)

        = prevMinEle // This is what we wanted