Получение элемента Min в стеке за время O(1)

причина, по которой я задаю этот вопрос, заключается в том, что я не понимаю, почему то, как я думаю, не может быть применено к этому конкретному вопросу

"как бы вы спроектировать стека, который, в дополнение к push и pop, также есть функция min, которая возвращает минимальный элемент? Push, pop и min должны работать в O (1) time"

мое основное решение:не было бы возможным, если бы у нас была переменная в стек класс, что всякий раз, когда мы были нажатие элемента в стек мы бы проверить, если это меньше чем наш мин переменной. Если это присвоить значение min, если не игнорировать.

вы все равно получите O (1), поскольку функция min будет;

int getMinimum(){
  return min;
}

почему это решение никогда не упоминается, или в чем виноват, как я думаю?

4 ответов


Это не сработало бы, если бы вы вытащили числа из стека.

Ex. 2,4,5,3,1. После того, как вы выкинете 1, каков ваш минимум?

решение сохранить стек минимумов, а не только одно значение. Если вы столкнулись со значением, которое меньше, чем равно текущему минимуму, вам нужно нажать его на min-stack.

Ex.

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

использовать связанный список, чтобы отслеживать минимальное значение, которое будет в голове.

обратите внимание, что linkedlist.app= append (мы помещаем значение в хвост ). LinkedList не.pre =prepend (мы ставим значение в качестве главы linkedlist)

стек общественных класса {

int[] elements;
int top;
Linkedlists min;

public Stack(int n) {
    elements = new int[n];
    top = 0;
    min = new Linkedlists();
}

public void realloc(int n) {
    int[] tab = new int[n];
    for (int i = 0; i < top; i++) {
        tab[i] = elements[i];
    }

    elements = tab;
}

public void push(int x) {
    if (top == elements.length) {
        realloc(elements.length * 2);
    }
    if (top == 0) {
        min.pre(x);
    } else if (x < min.head.data) {
        min.pre(x);
    } else {
        min.app(x);
    }
    elements[top++] = x;
}

public int pop() {

    int x = elements[--top];
    if (top == 0) {

    }
    if (this.getMin() == x) {
        min.head = min.head.next;
    }
    elements[top] = 0;
    if (4 * top < elements.length) {
        realloc((elements.length + 1) / 2);
    }

    return x;
}

public void display() {
    for (Object x : elements) {
        System.out.print(x + " ");
    }

}

public int getMin() {
    if (top == 0) {
        return 0;
    }
    return this.min.head.data;
}

public static void main(String[] args) {
    Stack stack = new Stack(4);
    stack.push(2);
    stack.push(3);
    stack.push(1);
    stack.push(4);
    stack.push(5);
    stack.pop();
    stack.pop();
    stack.pop();
    stack.push(1);
    stack.pop();
    stack.pop();
    stack.pop();
    stack.push(2);
    System.out.println(stack.getMin());
    stack.display();

}

}


Я нашел это решение здесь

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;
};

мы определяем переменную minEle, которая хранит текущий минимальный элемент в стеке. Теперь интересная часть заключается в том, как обрабатывать случай, когда минимальный элемент удален. Чтобы справиться с этим, мы нажимаем "2x – minEle" в стек вместо x, чтобы предыдущий минимальный элемент можно было получить с помощью текущего minEle и его значения, хранящегося в стеке. Ниже приведены подробные шаги и объяснение работы.

Push (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

как 2 * x-minEle меньше, чем x в push()?

x

// добавление x с обеих сторон

x-minEle + x

2 * x-minEle

мы можем заключить 2 * x-minEle

при появлении, если мы найдем элемент (y) меньше, чем текущая минела, мы найдем новую минелу = 2 * минеле – y.


как предыдущий минимальный элемент, prevMinEle, 2 * minEle-y?

в pop () является y выскочил элемент?

/ / мы нажали y как 2x-prevMinEle. Вот!--4-->

// prevMinEle является минеле до y был вставлен

y = 2 * x-prevMinEle

// значение minEle было сделано равным x minEle = x .

новая минела = 2 * minEle-y

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

        = prevMinEle // This is what we wanted