zaprojektuj stos taki, że getMinimum () powinno mieć wartość O (1)


118

To jedno z pytań do wywiadu. Musisz zaprojektować stos, który przechowuje wartość całkowitą w taki sposób, że funkcja getMinimum () powinna zwracać minimum elementu stosu.

Na przykład: rozważ poniższy przykład

przypadek 1

5 -> TOP
1
4
6
2

Wywołanie metody getMinimum () powinno zwrócić 1, czyli element minimum 
w stosie. 

sprawa nr 2

stack.pop ()
stack.pop ()

Uwaga: zarówno 5, jak i 1 są usuwane ze stosu. Więc po tym stos
wygląda jak,

4 -> TOP
6
2

Kiedy wywoływana jest funkcja getMinimum (), powinna zwrócić 2, czyli minimum w 
stos.

Constriants:

  1. getMinimum powinno zwrócić minimalną wartość w O (1)
  2. Podczas projektowania należy również wziąć pod uwagę ograniczenia przestrzenne, a jeśli używasz dodatkowej przestrzeni, powinna mieć stałą przestrzeń.

Odpowiedzi:


180

EDYCJA: To nie spełnia ograniczenia „stałej przestrzeni” - w zasadzie podwaja wymaganą przestrzeń. Bardzo wątpię, czy istnieje rozwiązanie, które tego nie robi, bez niszczenia gdzieś złożoności środowiska wykonawczego (np. Tworzenie push / pop O (n)). Zwróć uwagę, że nie zmienia to złożoności wymaganej przestrzeni, np. Jeśli masz stos z wymaganiami dotyczącymi miejsca O (n), nadal będzie to O (n) z innym stałym współczynnikiem.

Rozwiązanie niestałej przestrzeni

Zachowaj „zduplikowany” stos „minimum wszystkich wartości niżej w stosie”. Kiedy usuniesz główny stos, zdejmij również minimalny stos. Kiedy wepchniesz główny stos, wepchnij nowy element lub bieżące min, w zależności od tego, która z tych wartości jest niższa. getMinimum()jest następnie implementowany jako sprawiedliwy minStack.peek().

Korzystając z twojego przykładu, mielibyśmy:

Real stack        Min stack

5  --> TOP        1
1                 1
4                 2
6                 2
2                 2

Po dwukrotnym wystrzeleniu otrzymujesz:

Real stack        Min stack

4                 2
6                 2
2                 2

Daj mi znać, jeśli to nie wystarczy. To proste, kiedy się go pogłębisz, ale na początku może to zająć trochę drapania po głowie :)

(Wadą jest oczywiście to, że podwaja zapotrzebowanie na miejsce. Czas wykonania nie ulega jednak znacznemu pogorszeniu - tj. Nadal jest to ta sama złożoność).

EDYCJA: istnieje odmiana, która jest nieco bardziej skomplikowana, ale ogólnie ma lepszą przestrzeń. Nadal mamy minimalny stos, ale wyskakujemy z niego tylko wtedy, gdy wartość, którą zdejmujemy z głównego stosu, jest równa tej na minimalnym stosie. Mamy tylko naciskać na min stosie, gdy wartość pchanych na głównym stosie jest mniejsza niż lub równa bieżącej wartości min. Pozwala to na zduplikowane wartości minimalne. getMinimum()to wciąż tylko podglądowa operacja. Na przykład, biorąc oryginalną wersję i ponownie wciskając 1, otrzymamy:

Real stack        Min stack

1  --> TOP        1
5                 1
1                 2
4                 
6                 
2                 

Wyskakiwanie z powyższego wyskakuje z obu stosów, ponieważ 1 == 1, pozostawiając:

Real stack        Min stack

5  --> TOP        1
1                 2
4                 
6                 
2                 

Popping ponownie wyskakuje tylko z głównego stosu, ponieważ 5> 1:

Real stack        Min stack

1                 1
4                 2
6                 
2                 

Popping ponownie powoduje zdemaskowanie obu stosów, ponieważ 1 == 1:

Real stack        Min stack

4                 2
6                 
2                 

Kończy się to z taką samą złożonością miejsca w najgorszym przypadku (dwukrotność oryginalnego stosu), ale znacznie lepszym wykorzystaniem miejsca, jeśli rzadko otrzymujemy „nowe minimum lub równe”.

EDYCJA: Oto implementacja złego planu Pete'a. Nie przetestowałem tego dokładnie, ale myślę, że jest w porządku :)

using System.Collections.Generic;

public class FastMinStack<T>
{
    private readonly Stack<T> stack = new Stack<T>();
    // Could pass this in to the constructor
    private readonly IComparer<T> comparer = Comparer<T>.Default;

    private T currentMin;

    public T Minimum
    {
        get { return currentMin; }
    }

    public void Push(T element)
    {
        if (stack.Count == 0 ||
            comparer.Compare(element, currentMin) <= 0)
        {
            stack.Push(currentMin);
            stack.Push(element);
            currentMin = element;
        }
        else
        {
            stack.Push(element);
        }
    }

    public T Pop()
    {
        T ret = stack.Pop();
        if (comparer.Compare(ret, currentMin) == 0)
        {
            currentMin = stack.Pop();
        }
        return ret;
    }
}

3
Sprytny! @Ganesh: Dlaczego środowisko wykonawcze miałoby być problemem? Zajmie to tylko dwa razy dłużej niż pojedynczy stack, czyli nadal jest to czas O (1) na push () i pop (), a także na getMinimum () - to doskonała wydajność!
j_random_hacker

4
Jeśli masz jedną zmienną, co się stanie, gdy w Twoim przykładzie zdejmiesz „1”? Musi się okazać, że poprzednie minimum wynosiło „2” - czego nie może zrobić bez przeszukiwania wszystkiego.
Jon Skeet

1
@Ganesh: Czy nie będziesz wtedy musiał znaleźć nowego minimum za pomocą wyszukiwania O (n) za każdym razem, gdy pop ()?
j_random_hacker

2
Czytając tylko swoje inne komentarze, kiedy mówisz „w samym projekcie stosu”, czy masz na myśli „w każdym elemencie”? Jeśli tak, nadal potencjalnie podwajasz wymagania dotyczące pamięci, w zależności od rozmiaru typu elementu. Koncepcyjnie to to samo, co dwa stosy.
Jon Skeet

1
@Ganesh: Niestety brak dodatkowego stosu oznacza, że ​​nie możemy dokonać optymalizacji oszczędzającej miejsce, którą zawarłem powyżej. Utrzymywanie razem „minimum i elementu” jest prawdopodobnie bardziej wydajne niż dwa stosy tego samego rozmiaru (mniej narzutów - tablice, węzły list itp.), Chociaż będzie to zależeć od języka.
Jon Skeet

41

Dodaj pole do przechowywania wartości minimalnej i zaktualizuj je podczas operacji Pop () i Push (). W ten sposób getMinimum () będzie miało wartość O (1), ale Pop () i Push () będą musiały wykonać trochę więcej pracy.

Jeśli zdejmie się minimalną wartość, Pop () będzie równe O (n), w przeciwnym razie obie będą nadal O (1). Podczas zmiany rozmiaru Push () staje się O (n), zgodnie z implementacją Stack.

Oto szybka implementacja

public sealed class MinStack {
    private int MinimumValue;
    private readonly Stack<int> Stack = new Stack<int>();

    public int GetMinimum() {
        if (IsEmpty) {
            throw new InvalidOperationException("Stack is empty");
        }
        return MinimumValue;
    }

    public int Pop() {
        var value = Stack.Pop();
        if (value == MinimumValue) {
            MinimumValue = Stack.Min();
        }
        return value;
    }

    public void Push(int value) {
        if (IsEmpty || value < MinimumValue) {
            MinimumValue = value;
        }
        Stack.Push(value);
    }

    private bool IsEmpty { get { return Stack.Count() == 0; } }
}

przepraszam, nie rozumiem, dlaczego pop () i push () będą cierpieć?
Ganesh M

11
W pop () należy znaleźć „nowy” element minimum, który przyjmuje O (n). Push () nie ucierpi, ponieważ ta operacja jest nadal O (1).
Georg Schölly

4
@sigjuice: poprawne. Myślę, że zmienię słowo „cierpieć” na coś mniej dramatycznego :)
Brian Rasmussen

2
@Ganesh M "pole dodawania elementów" jeśli masz dodatkowe pole w swoich N elementach, to nie jest to stała przestrzeń, ale O (N) dodatkowe.
Pete Kirkham

1
Jeśli minimalna wartość zostanie wyjęta ze stosu podczas operacji, to w jaki sposób zostanie znaleziona następna minimalna wartość? Ta metoda nie obsługuje tego scenariusza ...
Sharat Chandra,

16
public class StackWithMin {
    int min;
    int size;
    int[] data = new int[1024];

    public void push ( int val ) {
        if ( size == 0 ) {
            data[size] = val;
            min = val;
        } else if ( val < min) {
            data[size] = 2 * val - min;
            min = val;

            assert (data[size] < min); 
        } else {
            data[size] = val;
        }

        ++size;

        // check size and grow array
    }

    public int getMin () {
        return min;
    }

    public int pop () {
        --size;

        int val = data[size];

        if ( ( size > 0 ) && ( val < min ) ) {
            int prevMin = min;
            min += min - val;
            return prevMin;
        } else {
            return val;
        }
    }

    public boolean isEmpty () {
        return size == 0;
    }

    public static void main (String...args) {
        StackWithMin stack = new StackWithMin();

        for ( String arg: args ) 
            stack.push( Integer.parseInt( arg ) );

        while ( ! stack.isEmpty() ) {
            int min = stack.getMin();
            int val = stack.pop();

            System.out.println( val + " " + min );
        }

        System.out.println();
    }

}

Przechowuje bieżące minimum jawnie, a jeśli minimalne zmiany, zamiast przesuwać wartość, wypycha wartość z tą samą różnicą po drugiej stronie nowego minimum (jeśli min = 7 i naciśniesz 5, zamiast tego wypycha 3 (5- | 7-5 | = 3) i ustawia min na 5; jeśli następnie zdejmiesz 3, gdy min wynosi 5, zobaczy, że wartość zderzaka jest mniejsza niż min, więc odwraca procedurę, aby uzyskać 7 dla nowej minuty, a następnie zwraca poprzednią min). Ponieważ każda wartość, która nie powoduje zmiany, bieżące minimum jest większe niż bieżące minimum, masz coś, co może być użyte do rozróżnienia między wartościami, które zmieniają minimum, a tymi, które nie.

W językach, które używają liczb całkowitych o stałym rozmiarze, pożyczasz trochę miejsca z reprezentacji wartości, więc może to spowodować niedopełnienie, a potwierdzenie zakończy się niepowodzeniem. Ale poza tym jest to stała dodatkowa przestrzeń i wszystkie operacje są nadal O (1).

Stosy, które zamiast tego są oparte na połączonych listach, mają inne miejsca, z których można trochę pożyczyć, na przykład w C najmniej znaczący bit następnego wskaźnika lub w Javie typ obiektów na połączonej liście. W przypadku języka Java oznacza to, że jest używane więcej miejsca w porównaniu do ciągłego stosu, ponieważ masz narzut obiektu na łącze:

public class LinkedStackWithMin {
    private static class Link {
        final int value;
        final Link next;

        Link ( int value, Link next ) {
            this.value = value;
            this.next = next;
        }

        int pop ( LinkedStackWithMin stack ) {
            stack.top = next;
            return value;
        }
    }

    private static class MinLink extends Link {
        MinLink ( int value, Link next ) {
            super( value, next );
        }

        int pop ( LinkedStackWithMin stack ) {
            stack.top = next;
            int prevMin = stack.min;
            stack.min = value;
            return prevMin;
        }
    }

    Link top;
    int min;

    public LinkedStackWithMin () {
    }

    public void push ( int val ) {
        if ( ( top == null ) || ( val < min ) ) {
            top = new MinLink(min, top);
            min = val;
        } else {
            top = new Link(val, top);
        }
    }

    public int pop () {
        return top.pop(this);
    }

    public int getMin () {
        return min;
    }

    public boolean isEmpty () {
        return top == null;
    }

W C nie ma narzutu i możesz pożyczyć lsb następnego wskaźnika:

typedef struct _stack_link stack_with_min;

typedef struct _stack_link stack_link;

struct _stack_link {
    size_t  next;
    int     value;
};

stack_link* get_next ( stack_link* link ) 
{
    return ( stack_link * )( link -> next & ~ ( size_t ) 1 );
}

bool is_min ( stack_link* link )
{
    return ( link -> next & 1 ) ! = 0;
}

void push ( stack_with_min* stack, int value )
{
    stack_link *link = malloc ( sizeof( stack_link ) );

    link -> next = ( size_t ) stack -> next;

    if ( (stack -> next == 0) || ( value == stack -> value ) ) {
        link -> value = stack -> value;
        link -> next |= 1; // mark as min
    } else {
        link -> value = value;
    }

    stack -> next = link;
}

etc.;

Jednak żaden z nich nie jest naprawdę O (1). W praktyce nie wymagają więcej miejsca, ponieważ wykorzystują dziury w reprezentacjach liczb, obiektów lub wskaźników w tych językach. Ale teoretyczna maszyna, która używałaby bardziej zwartej reprezentacji, wymagałaby dodania dodatkowego bitu do tej reprezentacji w każdym przypadku.


+1 bardzo elegancka ... trywialnie przeniesiona wersja C ++ działająca w ideone tutaj . Twoje zdrowie.
Tony Delroy

W Javie da to zły wynik, pop()jeśli ostatnią wypchniętą wartością była Integer.MIN_VALUE(np. Push 1, push Integer.MIN_VALUE, pop). Wynika to z niedomiaru, jak wspomniano powyżej. W przeciwnym razie działa dla wszystkich wartości całkowitych.
Theo

13

Znalazłem rozwiązanie, które spełnia wszystkie wspomniane ograniczenia (operacje na stałym czasie) i stałą dodatkową przestrzeń .

Pomysł polega na zapisaniu różnicy między wartością minimalną a liczbą wejściową i zaktualizowaniu wartości minimalnej, jeśli nie jest już wartością minimalną.

Kod wygląda następująco:

public class MinStack {
    long min;
    Stack<Long> stack;

    public MinStack(){
        stack = new Stack<>();
    }

    public void push(int x) {
        if (stack.isEmpty()) {
            stack.push(0L);
            min = x;
        } else {
            stack.push(x - min); //Could be negative if min value needs to change
            if (x < min) min = x;
        }
    }

    public int pop() {
        if (stack.isEmpty()) return;

        long pop = stack.pop();

        if (pop < 0) {
            long ret = min
            min = min - pop; //If negative, increase the min value
            return (int)ret;
        }
        return (int)(pop + min);

    }

    public int top() {
        long top = stack.peek();
        if (top < 0) {
            return (int)min;
        } else {
           return (int)(top + min);
        }
    }

    public int getMin() {
        return (int)min;
    }
}

Kredyt trafia do: https://leetcode.com/discuss/15679/share-my-java-solution-with-only-one-stack


Ten działa. Próbowałem też z liczbami ujemnymi na stosie. I wystarczająco proste do zapamiętania. Dzięki.
r9891

7

Jakie są ograniczenia czasu wykonywania pushi pop? Jeśli nie wymaga się, aby były stałe, po prostu oblicz minimalną wartość w tych dwóch operacjach (czyniąc je O ( n )). W przeciwnym razie nie widzę, jak można to zrobić ze stałą dodatkową przestrzenią.


4
+1, hehe ... Stara sztuczka „naginania reguł” ... W podobny sposób znam algorytm sortowania, który sortuje tablicę o dowolnej wielkości w czasie O (1), ale pierwszy dostęp do dowolnego elementu wynik pociąga za sobą obciążenie O (nlog n) ... :)
j_random_hacker

3
W Haskell wszystko jest w ciągłym czasie! (chyba że chcesz wydrukować wynik)
Henk

1
+1 za zwrócenie uwagi na słabą specyfikację problemu. „Nie rozumiem, jak to można zrobić” - ja też nie, ale rozwiązanie Pete'a Kirkhama robi to bardzo elegancko…
Tony Delroy

1

Oto mój kod, który działa z O (1). Poprzedni kod, który opublikowałem, miał problem z wyskakiwaniem minimalnego elementu. Zmodyfikowałem swój kod. Ten używa innego stosu, który utrzymuje minimalny element na stosie powyżej aktualnie wypchniętego elementu.

 class StackDemo
{
    int[] stk = new int[100];
    int top;
    public StackDemo()
    {
        top = -1;
    }
    public void Push(int value)
    {
        if (top == 100)
            Console.WriteLine("Stack Overflow");
        else
            stk[++top] = value;
    }
    public bool IsEmpty()
    {
        if (top == -1)
            return true;
        else
            return false;
    }
    public int Pop()
    {
        if (IsEmpty())
        {
            Console.WriteLine("Stack Underflow");
            return 0;
        }
        else
            return stk[top--];
    }
    public void Display()
    {
        for (int i = top; i >= 0; i--)
            Console.WriteLine(stk[i]);
    }
}
class MinStack : StackDemo
{
    int top;
    int[] stack = new int[100];
    StackDemo s1; int min;
    public MinStack()
    {
        top = -1;
        s1 = new StackDemo();
    }
    public void PushElement(int value)
    {
        s1.Push(value);
        if (top == 100)
            Console.WriteLine("Stack Overflow");
        if (top == -1)
        {
            stack[++top] = value;
            stack[++top] = value;   
        }
        else
        {
            //  stack[++top]=value;
            int ele = PopElement();
            stack[++top] = ele;
            int a = MininmumElement(min, value);
              stack[++top] = min;

                stack[++top] = value;
                stack[++top] = a;


        }
    }
    public int PopElement()
    {

        if (top == -1)
            return 1000;
        else
        {
            min = stack[top--];
            return stack[top--];
        }

    }
    public int PopfromStack()
    {
        if (top == -1)
            return 1000;
        else
        {
            s1.Pop();
            return PopElement();
        }
    }
    public int MininmumElement(int a,int b)
    {
        if (a > b)
            return b;
        else
            return a;
    }
    public int StackTop()
    {
        return stack[top];
    }
    public void DisplayMinStack()
    {
        for (int i = top; i >= 0; i--)
            Console.WriteLine(stack[i]);
    }
}
class Program
{
    static void Main(string[] args)
    {
        MinStack ms = new MinStack();
        ms.PushElement(15);
        ms.PushElement(2);
        ms.PushElement(1);
        ms.PushElement(13);
        ms.PushElement(5);
        ms.PushElement(21);
        Console.WriteLine("Min Stack");
        ms.DisplayMinStack();
        Console.WriteLine("Minimum Element:"+ms.StackTop());
        ms.PopfromStack();
        ms.PopfromStack();
        ms.PopfromStack();
        ms.PopfromStack();

        Console.WriteLine("Min Stack");
        ms.DisplayMinStack();
        Console.WriteLine("Minimum Element:" + ms.StackTop());
        Thread.Sleep(1000000);
    }
}

3
Proszę wspomnieć o języku programowania używanym tutaj do pisania kodu. Pomaga potencjalnym odwiedzającym zorientować się, co się dzieje w oparciu o składnię. Zakładam, że to C #, ale co jeśli ktoś nie?
realPK

1

Użyłem innego rodzaju stosu. Oto realizacja.

//
//  main.cpp
//  Eighth
//
//  Created by chaitanya on 4/11/13.
//  Copyright (c) 2013 cbilgika. All rights reserved.
//

#include <iostream>
#include <limits>
using namespace std;
struct stack
{
    int num;
    int minnum;
}a[100];

void push(int n,int m,int &top)
{

    top++;
    if (top>=100) {
        cout<<"Stack Full";
        cout<<endl;
    }
    else{
        a[top].num = n;
        a[top].minnum = m;
    }


}

void pop(int &top)
{
    if (top<0) {
        cout<<"Stack Empty";
        cout<<endl;
    }
    else{
       top--; 
    }


}
void print(int &top)
{
    cout<<"Stack: "<<endl;
    for (int j = 0; j<=top ; j++) {
        cout<<"("<<a[j].num<<","<<a[j].minnum<<")"<<endl;
    }
}


void get_min(int &top)
{
    if (top < 0)
    {
        cout<<"Empty Stack";
    }
    else{
        cout<<"Minimum element is: "<<a[top].minnum;
    }
    cout<<endl;
}

int main()
{

    int top = -1,min = numeric_limits<int>::min(),num;
    cout<<"Enter the list to push (-1 to stop): ";
    cin>>num;
    while (num!=-1) {
        if (top == -1) {
            min = num;
            push(num, min, top);
        }
        else{
            if (num < min) {
                min = num;
            }
            push(num, min, top);
        }
        cin>>num;
    }
    print(top);
    get_min(top);
    return 0;
}

Wynik:

Enter the list to push (-1 to stop): 5
1
4
6
2
-1
Stack: 
(5,5)
(1,1)
(4,1)
(6,1)
(2,1)
Minimum element is: 1

Spróbuj. Myślę, że to odpowiada na pytanie. Drugi element każdej pary podaje minimalną wartość widzianą podczas wstawiania tego elementu.


1

Wrzucam tutaj cały kod, aby znaleźć min i max w podanym stosie.

Złożoność czasowa będzie wynosić O (1) ..

package com.java.util.collection.advance.datastructure;

/**
 * 
 * @author vsinha
 *
 */
public abstract interface Stack<E> {

    /**
     * Placing a data item on the top of the stack is called pushing it
     * @param element
     * 
     */
    public abstract void push(E element);


    /**
     * Removing it from the top of the stack is called popping it
     * @return the top element
     */
    public abstract E pop();

    /**
     * Get it top element from the stack and it 
     * but the item is not removed from the stack, which remains unchanged
     * @return the top element
     */
    public abstract E peek();

    /**
     * Get the current size of the stack.
     * @return
     */
    public abstract int size();


    /**
     * Check whether stack is empty of not.
     * @return true if stack is empty, false if stack is not empty
     */
    public abstract boolean empty();



}



package com.java.util.collection.advance.datastructure;

@SuppressWarnings("hiding")
public abstract interface MinMaxStack<Integer> extends Stack<Integer> {

    public abstract int min();

    public abstract int max();

}


package com.java.util.collection.advance.datastructure;

import java.util.Arrays;

/**
 * 
 * @author vsinha
 *
 * @param <E>
 */
public class MyStack<E> implements Stack<E> {

    private E[] elements =null;
    private int size = 0;
    private int top = -1;
    private final static int DEFAULT_INTIAL_CAPACITY = 10;


    public MyStack(){
        // If you don't specify the size of stack. By default, Stack size will be 10
        this(DEFAULT_INTIAL_CAPACITY);
    }

    @SuppressWarnings("unchecked")
    public MyStack(int intialCapacity){
        if(intialCapacity <=0){
            throw new IllegalArgumentException("initial capacity can't be negative or zero");
        }
        // Can't create generic type array
        elements =(E[]) new Object[intialCapacity];
    }

    @Override
    public void push(E element) {
        ensureCapacity();
        elements[++top] = element;
        ++size;
    }

    @Override
    public E pop() {
        E element = null;
        if(!empty()) {
            element=elements[top];
            // Nullify the reference
            elements[top] =null;
            --top;
            --size;
        }
        return element;
    }

    @Override
    public E peek() {
        E element = null;
        if(!empty()) {
            element=elements[top];
        }
        return element;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean empty() {
        return size == 0;
    }

    /**
     * Increases the capacity of this <tt>Stack by double of its current length</tt> instance, 
     * if stack is full 
     */
    private void ensureCapacity() {
        if(size != elements.length) {
            // Don't do anything. Stack has space.
        } else{
            elements = Arrays.copyOf(elements, size *2);
        }
    }

    @Override
    public String toString() {
        return "MyStack [elements=" + Arrays.toString(elements) + ", size="
                + size + ", top=" + top + "]";
    }


}


package com.java.util.collection.advance.datastructure;

/**
 * Time complexity will be O(1) to find min and max in a given stack.
 * @author vsinha
 *
 */
public class MinMaxStackFinder extends MyStack<Integer> implements MinMaxStack<Integer> {

    private MyStack<Integer> minStack;

    private MyStack<Integer> maxStack;

    public MinMaxStackFinder (int intialCapacity){
        super(intialCapacity);
        minStack =new MyStack<Integer>();
        maxStack =new MyStack<Integer>();

    }
    public void push(Integer element) {
        // Current element is lesser or equal than min() value, Push the current element in min stack also.
        if(!minStack.empty()) {
            if(min() >= element) {
                minStack.push(element);
            }
        } else{
            minStack.push(element);
        }
        // Current element is greater or equal than max() value, Push the current element in max stack also.
        if(!maxStack.empty()) {
            if(max() <= element) {
                maxStack.push(element);
            }
        } else{
            maxStack.push(element);
        }
        super.push(element);
    }


    public Integer pop(){
        Integer curr = super.pop();
        if(curr !=null) {
            if(min() == curr) {
                minStack.pop();
            } 

            if(max() == curr){
                maxStack.pop();
            }
        }
        return curr;
    }


    @Override
    public int min() {
        return minStack.peek();
    }

    @Override
    public int max() {
        return maxStack.peek();
    }


    @Override
    public String toString() {
        return super.toString()+"\nMinMaxStackFinder [minStack=" + minStack + "\n maxStack="
                + maxStack + "]" ;
    }




}

// You can use the below program to execute it.

package com.java.util.collection.advance.datastructure;

import java.util.Random;

public class MinMaxStackFinderApp {

    public static void main(String[] args) {
        MinMaxStack<Integer> stack =new MinMaxStackFinder(10);
        Random random =new Random();
        for(int i =0; i< 10; i++){
            stack.push(random.nextInt(100));
        }
        System.out.println(stack);
        System.out.println("MAX :"+stack.max());
        System.out.println("MIN :"+stack.min());

        stack.pop();
        stack.pop();
        stack.pop();
        stack.pop();
        stack.pop();

        System.out.println(stack);
        System.out.println("MAX :"+stack.max());
        System.out.println("MIN :"+stack.min());
    }
}

Daj mi znać, jeśli napotkasz jakiś problem

Dzięki, Vikash


1

Możesz rozszerzyć swoją oryginalną klasę stosu i po prostu dodać do niej śledzenie min. Pozwól, aby oryginalna klasa nadrzędna obsługiwała wszystko inne w zwykły sposób.

public class StackWithMin extends Stack<Integer> {  

    private Stack<Integer> min;

    public StackWithMin() {
        min = new Stack<>();
    }

    public void push(int num) {
        if (super.isEmpty()) {
            min.push(num);
        } else if (num <= min.peek()) {
            min.push(num);
        }
        super.push(num);
    }

    public int min() {
        return min.peek();
    }

    public Integer pop() {
        if (super.peek() == min.peek()) {
            min.pop();
        }
        return super.pop();
    }   
}

To rozwiązanie wykorzystuje również dodatkową przestrzeń pod względem Stack <Integer> min.
Arpit,

1

Oto moje rozwiązanie w javie przy użyciu listy ulubionych.

class Stack{
    int min;
    Node top;
    static class Node{
        private int data;
        private Node next;
        private int min;

        Node(int data, int min){
           this.data = data;
           this.min = min;
           this.next = null; 
    }
}

  void push(int data){
        Node temp;
        if(top == null){
            temp = new Node(data,data);
            top = temp;
            top.min = data;
        }
        if(top.min > data){
            temp = new Node(data,data);
            temp.next = top;
            top = temp;
        } else {
            temp = new Node(data, top.min);
            temp.next = top;
            top = temp;
        }
  }

  void pop(){
    if(top != null){
        top = top.next;
    }
  }

  int min(){
    return top.min;
  }

}


1

Załóżmy, że stos, nad którym będziemy pracować, jest następujący:

6 , minvalue=2
2 , minvalue=2
5 , minvalue=3
3 , minvalue=3
9 , minvalue=7
7 , minvalue=7
8 , minvalue=8

W powyższej reprezentacji stos jest budowany tylko przez lewą wartość, a [minvalue] prawej wartości jest zapisywana tylko w celach ilustracyjnych, która będzie przechowywana w jednej zmiennej.

Rzeczywisty problem polega na tym, że wartość, która jest minimalną wartością get, jest usuwana w tym momencie, skąd możemy wiedzieć, jaki jest następny minimalny element bez iteracji po stosie.

Na przykład w naszym stosie, gdy wyskoczyło 6 get, wiemy, że nie jest to element minimalny, ponieważ element minimalny wynosi 2, więc możemy bezpiecznie usunąć to bez aktualizowania naszej wartości min.

Ale kiedy wyskoczymy 2, widzimy, że minimalna wartość wynosi teraz 2, a jeśli to get wyskoczyło, musimy zaktualizować minimalną wartość do 3.

Punkt 1:

Teraz, jeśli przyjrzysz się uważnie, musimy wygenerować minvalue = 3 z tego konkretnego stanu [2, minvalue = 2]. lub jeśli pójdziesz depper w stosie, musimy wygenerować minvalue = 7 z tego konkretnego stanu [3, minvalue = 3] lub jeśli pójdziesz bardziej depper w stosie, musimy wygenerować minvalue = 8 z tego konkretnego stanu [7, minvalue = 7]

Czy zauważyłeś coś wspólnego we wszystkich powyższych 3 przypadkach, wartość, którą musimy wygenerować, zależy od dwóch zmiennych, które są równe. Poprawny. Dlaczego tak się dzieje, ponieważ kiedy przesuwamy jakiś element mniejszy niż bieżąca minvalue, to po prostu umieszczamy ten element na stosie i aktualizujemy tę samą liczbę również w minvalue.

Punkt 2:

Więc w zasadzie przechowujemy duplikat tej samej liczby raz na stosie i raz w zmiennej minvalue. Musimy skupić się na unikaniu tego powielania i przechowywać jakieś przydatne dane na stosie lub minimalną wartość, aby wygenerować poprzednie minimum, jak pokazano w przypadku powyżej.

Skoncentrujmy się na tym, co powinniśmy przechowywać na stosie, gdy wartość do przechowywania w push jest mniejsza niż minimalna wartość. Nazwijmy tę zmienną y, więc teraz nasz stos będzie wyglądał mniej więcej tak:

6 , minvalue=2
y1 , minvalue=2
5 , minvalue=3
y2 , minvalue=3
9 , minvalue=7
y3 , minvalue=7
8 , minvalue=8

Zmieniłem ich nazwy na y1, y2, y3, aby uniknąć nieporozumień, że wszystkie będą miały taką samą wartość.

Punkt3:

Teraz spróbujmy znaleźć jakieś ograniczenie na y1, y2 i y3. Czy pamiętasz, kiedy dokładnie musimy zaktualizować minvalue podczas wykonywania pop (), tylko wtedy, gdy usunęliśmy element, który jest równy minvalue. Jeśli wystrzelimy coś większego niż minvalue, nie musimy aktualizować minvalue. Tak więc, aby wyzwolić aktualizację minvalue, y1, y2 i y3 powinny być mniejsze niż odpowiadająca im minvalue. [Uwolnimy równość, aby uniknąć powielania [Point2]], więc ograniczenie wynosi [y <minValue].

Teraz wróćmy do wypełnienia y, musimy wygenerować jakąś wartość i umieścić y w momencie wypychania, pamiętaj. Przyjmijmy, że wartością, która nadchodzi dla push jest x, która jest mniejsza niż wartość prevMinvalue, a wartością, którą faktycznie wepchniemy na stosie, będzie y. Więc jedno jest oczywiste, że newMinValue = x i y <newMinvalue.

Teraz musimy obliczyć y (pamiętaj, że y może być dowolną liczbą, która jest mniejsza niż newMinValue (x), więc musimy znaleźć jakąś liczbę, która może spełnić nasze ograniczenie) za pomocą prevMinvalue i x (newMinvalue).

Let's do the math:
    x < prevMinvalue [Given]
    x - prevMinvalue < 0 
    x - prevMinValue + x < 0 + x [Add x on both side]
    2*x - prevMinValue < x      
this is the y which we were looking for less than x(newMinValue).
y = 2*x - prevMinValue. 'or' y = 2*newMinValue - prevMinValue 'or' y = 2*curMinValue - prevMinValue [taking curMinValue=newMinValue].

Więc w momencie wypychania x, jeśli jest mniejsze niż prevMinvalue, wtedy wciskamy y [2 * x-prevMinValue] i aktualizujemy newMinValue = x.

A w momencie pop, jeśli stos zawiera coś mniejszego niż minValue, to jest to nasz wyzwalacz do aktualizacji minVAlue. Musimy obliczyć prevMinValue z curMinValue i y. y = 2 * curMinValue - prevMinValue [Udowodniono] prevMinVAlue = 2 * curMinvalue - y.

2 * curMinValue - y to liczba, którą musimy teraz zaktualizować do prevMinValue.

Kod tej samej logiki jest wspólny poniżej ze złożonością czasu O (1) i przestrzeni O (1).

// C++ program to implement a stack that supports 
// getMinimum() in O(1) time and O(1) extra space. 
#include <bits/stdc++.h> 
using namespace std; 

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

    // Prints minimum element of MyStack 
    void getMin() 
    { 
        if (s.empty()) 
            cout << "Stack is empty\n"; 

        // variable minEle stores the minimum element 
        // in the stack. 
        else
            cout <<"Minimum Element in the stack is: "
                 << minEle << "\n"; 
    } 

    // Prints top element of MyStack 
    void peek() 
    { 
        if (s.empty()) 
        { 
            cout << "Stack is empty "; 
            return; 
        } 

        int t = s.top(); // Top element. 

        cout << "Top Most Element is: "; 

        // If t < minEle means minEle stores 
        // value of t. 
        (t < minEle)? cout << minEle: cout << t; 
    } 

    // Remove the top element from MyStack 
    void pop() 
    { 
        if (s.empty()) 
        { 
            cout << "Stack is empty\n"; 
            return; 
        } 

        cout << "Top Most Element Removed: "; 
        int t = s.top(); 
        s.pop(); 

        // Minimum will change as the minimum element 
        // of the stack is being removed. 
        if (t < minEle) 
        { 
            cout << minEle << "\n"; 
            minEle = 2*minEle - t; 
        } 

        else
            cout << t << "\n"; 
    } 

    // Removes top element from MyStack 
    void push(int x) 
    { 
        // Insert new number into the stack 
        if (s.empty()) 
        { 
            minEle = x; 
            s.push(x); 
            cout <<  "Number Inserted: " << x << "\n"; 
            return; 
        } 

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

        else
           s.push(x); 

        cout <<  "Number Inserted: " << x << "\n"; 
    } 
}; 

// Driver Code 
int main() 
{ 
    MyStack s; 
    s.push(3); 
    s.push(5); 
    s.getMin(); 
    s.push(2); 
    s.push(1); 
    s.getMin(); 
    s.pop(); 
    s.getMin(); 
    s.pop(); 
    s.peek(); 

    return 0; 
} 

0

Oto moja wersja realizacji.

 struct MyStack {
    int element;
    int * CurrentMiniAddress;
 };

 void Push (wartość int)
 {
    // Stwórz swoją strukturę i wypełnij wartość
    MyStack S = new MyStack ();
    S-> element = wartość;

    if (Stack.Empty ())
    {    
        // Ponieważ stos jest pusty, wskaż CurrentMiniAddress na siebie
        S-> CurrentMiniAddress = S;

    }
    jeszcze
    {
         // Stos nie jest pusty

         // Pobierz najwyższy element. Bez pop ()
         MyStack * TopElement = Stack.Top ();

         // Pamiętaj Zawsze element TOP wskazuje na
         // minimalny element w całym stosie
         if (S-> element CurrentMiniAddress-> element)
         {
            // Jeśli aktualna wartość to minimum w całym stosie
            // wtedy S wskazuje na siebie
            S-> CurrentMiniAddress = S;
         }
             jeszcze
             {
                 // Więc to nie jest minimum w całym stosie
                 // Spokojnie, TOP trzyma element minimum
                 S-> CurrentMiniAddress = TopElement-> CurrentMiniAddress;
             }

    }
        Stack.Add (S);
 }

 void Pop ()
 {
     if (! Stack.Empty ())
     {
        Stack.Pop ();
     }  
 }

 int GetMinimum (stos i stos)
 {
       if (! stack.Empty ())
       {
            MyStack * Top = stack.top ();
            // Góra zawsze wskazuje minimum x
            powrót Top-> CurrentMiniAddress-> element;
        }
 }

Zgadzam się, to wymaga dodatkowego elementu w twojej strukturze. Ale to eliminuje znalezienie minimum za każdym razem, gdy zderzamy element.
Ganesh M

1
Tak więc, skoro nie udało Ci się sprostać ograniczeniom wynikającym z pytania, czy dostałeś pracę?
Pete Kirkham

0
#include<stdio.h>
struct stack
{
    int data;
    int mindata;
}a[100];

void push(int *tos,int input)
{
    if (*tos > 100)
    {
        printf("overflow");
        return;
    }
    (*tos)++;
    a[(*tos)].data=input;
    if (0 == *tos)
        a[*tos].mindata=input;
    else if (a[*tos -1].mindata < input)
        a[*tos].mindata=a[*tos -1].mindata;
    else
        a[*tos].mindata=input;
}

int pop(int * tos)
{
    if (*tos <= -1)
    {
        printf("underflow");
        return -1;
    }
    return(a[(*tos)--].data);
}
void display(int tos)
{
    while (tos > -1)
    {
        printf("%d:%d\t",a[tos].data,a[tos].mindata);
        tos--;
    }    
}

int min(int tos)
{
   return(a[tos].mindata);
}
int main()
{
int tos=-1,x,choice;
while(1)
{
    printf("press 1-push,2-pop,3-mindata,4-display,5-exit ");
    scanf("%d",&choice);
    switch(choice)
    {
    case 1: printf("enter data to push");
            scanf("%d",&x);
            push(&tos,x);
            break;
    case 2: printf("the poped out data=%d ",pop(&tos));
            break;
    case 3: printf("The min peeped data:%d",min(tos));
            break;
    case 4: printf("The elements of stack \n");
            display(tos);
            break;
    default: exit(0);
}
}

0

Znalazłem to rozwiązanie tutaj

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

0
struct Node {
    let data: Int
    init(_ d:Int){
        data = d
    }
}

struct Stack {
    private var backingStore = [Node]()
    private var minArray = [Int]()

    mutating func push(n:Node) {
        backingStore.append(n)
        minArray.append(n.data)
        minArray.sort(>)
        minArray
    }

    mutating func pop() -> Node? {
        if(backingStore.isEmpty){
            return nil
        }

        let n = backingStore.removeLast()

        var found = false
        minArray = minArray.filter{
            if (!found && $0 == n.data) {
                found = true
                return false
            }
            return true
        }
        return n
    }

    func min() -> Int? {
        return minArray.last
    }
}

0
 class MyStackImplementation{
private final int capacity = 4;
int min;
int arr[] = new int[capacity];
int top = -1;

public void push ( int val ) {
top++;
if(top <= capacity-1){
    if(top == 0){
min = val;
arr[top] = val;
}
else if(val < min){
arr[top] = arr[top]+min;
min = arr[top]-min;
arr[top] = arr[top]-min;
}
else {
arr[top] = val;
}
System.out.println("element is pushed");
}
else System.out.println("stack is full");

}

 public void pop () {
top--;
   if(top > -1){ 

   min = arr[top];
}
else {min=0; System.out.println("stack is under flow");}

}
public int min(){
return min;
}

 public boolean isEmpty () {
    return top == 0;
}

public static void main(String...s){
MyStackImplementation msi = new MyStackImplementation();
msi.push(1);
msi.push(4);
msi.push(2);
msi.push(10);
System.out.println(msi.min);
msi.pop();
msi.pop();
msi.pop();
msi.pop();
msi.pop();
System.out.println(msi.min);

}
}

0
class FastStack {

    private static class StackNode {
        private Integer data;
        private StackNode nextMin;

        public StackNode(Integer data) {
            this.data = data;
        }

        public Integer getData() {
            return data;
        }

        public void setData(Integer data) {
            this.data = data;
        }

        public StackNode getNextMin() {
            return nextMin;
        }

        public void setNextMin(StackNode nextMin) {
            this.nextMin = nextMin;
        }

    }

    private LinkedList<StackNode> stack = new LinkedList<>();

    private StackNode currentMin = null;

    public void push(Integer item) {
        StackNode node = new StackNode(item);
        if (currentMin == null) {
            currentMin = node;
            node.setNextMin(null);
        } else if (item < currentMin.getData()) {
            StackNode oldMinNode = currentMin;
            node.setNextMin(oldMinNode);
            currentMin = node;
        }

        stack.addFirst(node);
    }

    public Integer pop() {
        if (stack.isEmpty()) {
            throw new EmptyStackException();
        }
        StackNode node = stack.peek();
        if (currentMin == node) {
            currentMin = node.getNextMin();
        }
        stack.removeFirst();
        return node.getData();
    }

    public Integer getMinimum() {
        if (stack.isEmpty()) {
            throw new NoSuchElementException("Stack is empty");
        }
        return currentMin.getData();
    }
}

0

Oto mój kod, który działa z O (1). Tutaj użyłem pary wektorów, która zawiera wartość, która została wypchnięta, a także zawiera minimalną wartość do tej przesuniętej wartości.


Oto moja wersja implementacji C ++.

vector<pair<int,int> >A;
int sz=0; // to keep track of the size of vector

class MinStack
{
public:
    MinStack()
    {
        A.clear();
        sz=0;
    }

    void push(int x)
    {
        int mn=(sz==0)?x: min(A[sz-1].second,x); //find the minimum value upto this pushed value
        A.push_back(make_pair(x,mn));
        sz++; // increment the size
    }

    void pop()
    {
        if(sz==0) return;
        A.pop_back(); // pop the last inserted element
        sz--;  // decrement size
    }

    int top()
    {
        if(sz==0)   return -1;  // if stack empty return -1
        return A[sz-1].first;  // return the top element
    }

    int getMin()
    {
        if(sz==0) return -1;
        return A[sz-1].second; // return the minimum value at sz-1 
    }
};

0
    **The task can be acheived by creating two stacks:**



import java.util.Stack;
    /*
     * 
     * Find min in stack using O(n) Space Complexity
     */
    public class DeleteMinFromStack {

        void createStack(Stack<Integer> primary, Stack<Integer> minStack, int[] arr) {
    /* Create main Stack and in parallel create the stack which contains the minimum seen so far while creating main Stack */
            primary.push(arr[0]);
            minStack.push(arr[0]);

            for (int i = 1; i < arr.length; i++) {
                primary.push(arr[i]);
                if (arr[i] <= minStack.peek())// Condition to check to push the value in minimum stack only when this urrent value is less than value seen at top of this stack */
                    minStack.push(arr[i]);
            }

        }

        int findMin(Stack<Integer> secStack) {
            return secStack.peek();
        }

        public static void main(String args[]) {

            Stack<Integer> primaryStack = new Stack<Integer>();
            Stack<Integer> minStack = new Stack<Integer>();

            DeleteMinFromStack deleteMinFromStack = new DeleteMinFromStack();

            int[] arr = { 5, 5, 6, 8, 13, 1, 11, 6, 12 };
            deleteMinFromStack.createStack(primaryStack, minStack, arr);
            int mimElement = deleteMinFromStack.findMin(primaryStack, minStack);
    /** This check for algorithm when the main Stack Shrinks by size say i as in loop below */
            for (int i = 0; i < 2; i++) {
                primaryStack.pop();
            }

            System.out.println(" Minimum element is " + mimElement);
        }

    }
/*
here in have tried to add for loop wherin the main tack can be shrinked/expaned so we can check the algorithm */

Co to dodaje, powiedzmy, do odpowiedzi Jona Skeeta ? Ile miejsca zajmuje to n w kierunku nieskończoności (patrz pytanie lub powiązana odpowiedź)? W przypadku języka programowania, który twierdzi, że obsługuje obiekt obiektowy, bardziej odpowiednie wydaje się utworzenie (niezbyt abstrakcyjnego) typu danych / (generic) Class- MinStack? Zaleca się korzystanie z dokumentacji Java firmy OracleDeque .
siwobrody

(Dziękuję za wskazówki. (Komentarze do kodu powinny wyjaśniać, po co, jak i dlaczego - wzmianka, że ​​warunek jest warunkiem, nie jest pomocna. Lepiej nie wciskać pierwszego lub dwóch wierszy, osiągnięto, bieżący) , skurczony i rozszerzony …))
siwobrody

0

Praktyczna implementacja do znajdowania minimum w stosie obiektów zaprojektowanych przez użytkownika o nazwie: Szkoła

Stos będzie przechowywał Szkoły w stosie na podstawie rangi przypisanej szkole w określonym regionie, powiedzmy findMin () podaje szkole, gdzie otrzymamy maksymalną liczbę wniosków o Rekrutację, która z kolei ma być zdefiniowana przez komparator wykorzystujący rangę związaną ze szkołami w poprzednim sezonie.

The Code for same is below:


   package com.practical;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

public class CognitaStack {

    public School findMin(Stack<School> stack, Stack<School> minStack) {

        if (!stack.empty() && !minStack.isEmpty())
            return (School) minStack.peek();
        return null;
    }

    public School removeSchool(Stack<School> stack, Stack<School> minStack) {

        if (stack.isEmpty())
            return null;
        School temp = stack.peek();
        if (temp != null) {
            // if(temp.compare(stack.peek(), minStack.peek())<0){
            stack.pop();
            minStack.pop();
            // }

            // stack.pop();
        }
        return stack.peek();
    }

    public static void main(String args[]) {

        Stack<School> stack = new Stack<School>();
        Stack<School> minStack = new Stack<School>();

        List<School> lst = new LinkedList<School>();

        School s1 = new School("Polam School", "London", 3);
        School s2 = new School("AKELEY WOOD SENIOR SCHOOL", "BUCKINGHAM", 4);
        School s3 = new School("QUINTON HOUSE SCHOOL", "NORTHAMPTON", 2);
        School s4 = new School("OAKLEIGH HOUSE SCHOOL", " SWANSEA", 5);
        School s5 = new School("OAKLEIGH-OAK HIGH SCHOOL", "Devon", 1);
        School s6 = new School("BritishInter2", "Devon", 7);

        lst.add(s1);
        lst.add(s2);
        lst.add(s3);
        lst.add(s4);
        lst.add(s5);
        lst.add(s6);

        Iterator<School> itr = lst.iterator();
        while (itr.hasNext()) {
            School temp = itr.next();
            if ((minStack.isEmpty()) || (temp.compare(temp, minStack.peek()) < 0)) { // minStack.peek().equals(temp)
                stack.push(temp);
                minStack.push(temp);
            } else {
                minStack.push(minStack.peek());
                stack.push(temp);
            }

        }

        CognitaStack cogStack = new CognitaStack();
        System.out.println(" Minimum in Stack is " + cogStack.findMin(stack, minStack).name);
        cogStack.removeSchool(stack, minStack);
        cogStack.removeSchool(stack, minStack);

        System.out.println(" Minimum in Stack is "
                + ((cogStack.findMin(stack, minStack) != null) ? cogStack.findMin(stack, minStack).name : "Empty"));
    }

}

Również obiekt szkolny przedstawia się następująco:

package com.practical;

import java.util.Comparator;

public class School implements Comparator<School> {

    String name;
    String location;
    int rank;

    public School(String name, String location, int rank) {
        super();
        this.name = name;
        this.location = location;
        this.rank = rank;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((location == null) ? 0 : location.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + rank;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        School other = (School) obj;
        if (location == null) {
            if (other.location != null)
                return false;
        } else if (!location.equals(other.location))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (rank != other.rank)
            return false;
        return true;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public int getRank() {
        return rank;
    }

    public void setRank(int rank) {
        this.rank = rank;
    }

    public int compare(School o1, School o2) {
        // TODO Auto-generated method stub
        return o1.rank - o2.rank;
    }

}

class SchoolComparator implements Comparator<School> {

    public int compare(School o1, School o2) {
        return o1.rank - o2.rank;
    }

}

Ten przykład obejmuje następujące zagadnienia: 1. Implementacja stosu dla obiektów zdefiniowanych przez użytkownika, tutaj szkoła 2. Implementacja metody hashcode () i equals () przy użyciu wszystkich pól obiektów do porównania 3. Praktyczna implementacja scenariusza, w którym rqeuire, aby uzyskać operację stosu zawiera, aby była w kolejności O (1)


Nie ma tagu językowego na to pytanie (wręcz przeciwnie :): language-agnosticproszę określić, czego używasz dla kodu (i wcześniej usuń spacje The Code for same is below:). Jak to obsługuje stack.pop()? (i push()?)
siwobrody

0

Oto implementacja PHP tego, co wyjaśniono w odpowiedzi Jona Skeeta, jako nieco lepszą implementację złożoności przestrzeni w celu uzyskania maksymalnego stosu w O (1).

<?php

/**
 * An ordinary stack implementation.
 *
 * In real life we could just extend the built-in "SplStack" class.
 */
class BaseIntegerStack
{
    /**
     * Stack main storage.
     *
     * @var array
     */
    private $storage = [];

    // ------------------------------------------------------------------------
    // Public API
    // ------------------------------------------------------------------------

    /**
     * Pushes to stack.
     *
     * @param  int $value New item.
     *
     * @return bool
     */
    public function push($value)
    {
        return is_integer($value)
            ? (bool) array_push($this->storage, $value)
            : false;
    }

    /**
     * Pops an element off the stack.
     *
     * @return int
     */
    public function pop()
    {
        return array_pop($this->storage);
    }

    /**
     * See what's on top of the stack.
     *
     * @return int|bool
     */
    public function top()
    {
        return empty($this->storage)
            ? false
            : end($this->storage);
    }

    // ------------------------------------------------------------------------
    // Magic methods
    // ------------------------------------------------------------------------

    /**
     * String representation of the stack.
     *
     * @return string
     */
    public function __toString()
    {
        return implode('|', $this->storage);
    }
} // End of BaseIntegerStack class

/**
 * The stack implementation with getMax() method in O(1).
 */
class Stack extends BaseIntegerStack
{
    /**
     * Internal stack to keep track of main stack max values.
     *
     * @var BaseIntegerStack
     */
    private $maxStack;

    /**
     * Stack class constructor.
     *
     * Dependencies are injected.
     *
     * @param BaseIntegerStack $stack Internal stack.
     *
     * @return void
     */
    public function __construct(BaseIntegerStack $stack)
    {
        $this->maxStack = $stack;
    }

    // ------------------------------------------------------------------------
    // Public API
    // ------------------------------------------------------------------------

    /**
     * Prepends an item into the stack maintaining max values.
     *
     * @param  int $value New item to push to the stack.
     *
     * @return bool
     */
    public function push($value)
    {
        if ($this->isNewMax($value)) {
            $this->maxStack->push($value);
        }

        parent::push($value);
    }

    /**
     * Pops an element off the stack maintaining max values.
     *
     * @return int
     */
    public function pop()
    {
        $popped = parent::pop();

        if ($popped == $this->maxStack->top()) {
            $this->maxStack->pop();
        }

        return $popped;
    }

    /**
     * Finds the maximum of stack in O(1).
     *
     * @return int
     * @see push()
     */
    public function getMax()
    {
        return $this->maxStack->top();
    }

    // ------------------------------------------------------------------------
    // Internal helpers
    // ------------------------------------------------------------------------

    /**
     * Checks that passing value is a new stack max or not.
     *
     * @param  int $new New integer to check.
     *
     * @return boolean
     */
    private function isNewMax($new)
    {
        return empty($this->maxStack) OR $new > $this->maxStack->top();
    }

} // End of Stack class

// ------------------------------------------------------------------------
// Stack Consumption and Test
// ------------------------------------------------------------------------
$stack = new Stack(
    new BaseIntegerStack
);

$stack->push(9);
$stack->push(4);
$stack->push(237);
$stack->push(5);
$stack->push(556);
$stack->push(15);

print "Stack: $stack\n";
print "Max: {$stack->getMax()}\n\n";

print "Pop: {$stack->pop()}\n";
print "Pop: {$stack->pop()}\n\n";

print "Stack: $stack\n";
print "Max: {$stack->getMax()}\n\n";

print "Pop: {$stack->pop()}\n";
print "Pop: {$stack->pop()}\n\n";

print "Stack: $stack\n";
print "Max: {$stack->getMax()}\n";

// Here's the sample output:
//
// Stack: 9|4|237|5|556|15
// Max: 556
//
// Pop: 15
// Pop: 556
//
// Stack: 9|4|237|5
// Max: 237
//
// Pop: 5
// Pop: 237
//
// Stack: 9|4
// Max: 9

0

Oto implementacja Jon Skeets Answer w języku C ++ . Może nie jest to najbardziej optymalny sposób implementacji, ale robi dokładnie to, co powinien.

class Stack {
private:
    struct stack_node {
        int val;
        stack_node *next;
    };
    stack_node *top;
    stack_node *min_top;
public:
    Stack() {
        top = nullptr;
        min_top = nullptr;
    }    
    void push(int num) {
        stack_node *new_node = nullptr;
        new_node = new stack_node;
        new_node->val = num;

        if (is_empty()) {
            top = new_node;
            new_node->next = nullptr;

            min_top = new_node;
            new_node->next = nullptr;
        } else {
            new_node->next = top;
            top = new_node;

            if (new_node->val <= min_top->val) {
                new_node->next = min_top;
                min_top = new_node;
            }
        }
    }

    void pop(int &num) {
        stack_node *tmp_node = nullptr;
        stack_node *min_tmp = nullptr;

        if (is_empty()) {
            std::cout << "It's empty\n";
        } else {
            num = top->val;
            if (top->val == min_top->val) {
                min_tmp = min_top->next;
                delete min_top;
                min_top = min_tmp;
            }
            tmp_node = top->next;
            delete top;
            top = tmp_node;
        }
    }

    bool is_empty() const {
        return !top;
    }

    void get_min(int &item) {
        item = min_top->val;
    }
};

A oto kierowca tej klasy

int main() {
    int pop, min_el;
    Stack my_stack;

    my_stack.push(4);
    my_stack.push(6);
    my_stack.push(88);
    my_stack.push(1);
    my_stack.push(234);
    my_stack.push(2);

    my_stack.get_min(min_el);
    cout << "Min: " << min_el << endl;

    my_stack.pop(pop);
    cout << "Popped stock element: " << pop << endl;

    my_stack.pop(pop);
    cout << "Popped stock element: " << pop << endl;

    my_stack.pop(pop);
    cout << "Popped stock element: " << pop << endl;

    my_stack.get_min(min_el);
    cout << "Min: " << min_el << endl;

    return 0;
}

Wynik:

Min: 1
Popped stock element: 2
Popped stock element: 234
Popped stock element: 1
Min: 4

0

Możemy to zrobić w O (n) czasie i O (1) złożoności przestrzeni, na przykład:

class MinStackOptimized:
  def __init__(self):
      self.stack = []
      self.min = None

  def push(self, x): 
      if not self.stack:
          # stack is empty therefore directly add
          self.stack.append(x)
          self.min = x 
      else:
          """
          Directly add (x-self.min) to the stack. This also ensures anytime we have a 
          negative number on the stack is when x was less than existing minimum
          recorded thus far.
          """
          self.stack.append(x-self.min)
          if x < self.min:
              # Update x to new min
              self.min = x 

  def pop(self):
      x = self.stack.pop()
      if x < 0:
          """ 
          if popped element was negative therefore this was the minimum
          element, whose actual value is in self.min but stored value is what
          contributes to get the next min. (this is one of the trick we use to ensure
          we are able to get old minimum once current minimum gets popped proof is given
          below in pop method), value stored during push was:
          (x - self.old_min) and self.min = x therefore we need to backtrack
          these steps self.min(current) - stack_value(x) actually implies to
              x (self.min) - (x - self.old_min)
          which therefore gives old_min back and therefore can now be set
          back as current self.min.
          """
          self.min = self.min - x 

  def top(self):
      x = self.stack[-1]
      if x < 0:
          """ 
          As discussed above anytime there is a negative value on stack, this
          is the min value so far and therefore actual value is in self.min,
          current stack value is just for getting the next min at the time
          this gets popped.
          """
          return self.min
      else:
          """ 
          if top element of the stack was positive then it's simple, it was
          not the minimum at the time of pushing it and therefore what we did
          was x(actual) - self.min(min element at current stage) let's say `y`
          therefore we just need to reverse the process to get the actual
          value. Therefore self.min + y, which would translate to
              self.min + x(actual) - self.min, thereby giving x(actual) back
          as desired.
          """
          return x + self.min

  def getMin(self):
      # Always self.min variable holds the minimum so for so easy peezy.
      return self.min

0

Myślę, że możesz po prostu użyć LinkedList w swojej implementacji stosu.

Kiedy pierwszy raz wypychasz wartość, umieszczasz tę wartość jako nagłówek listy połączonej.

następnie za każdym razem, gdy wciskasz wartość, jeśli nowa wartość <head.data, wykonaj operację prepand (co oznacza, że ​​głowa staje się nową wartością)

jeśli nie, wykonaj operację dołączania.

Kiedy robisz pop (), sprawdzasz, czy min == linkedlist.head.data, jeśli tak, to head = head.next;

Oto mój kod.

public class Stack {

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();

}

 }

Miej sekwencję liczb. W pętli, jeśli liczba jest parzysta, zdejmij dwa elementy. Wciśnij numer i wydrukuj minimum.
siwobrody

? Nie rozumiem twojego komentarza
Zok

Możemy dostosować metody pop (), aby sprawdzić, czy wartości górnej == 0, jeśli tak, to usunąć połączonej listy poprzez min.head = null, min.head.next = null
ZOK

0
public class MinStack<E>{

    private final LinkedList<E> mainStack = new LinkedList<E>();
    private final LinkedList<E> minStack = new LinkedList<E>();
    private final Comparator<E> comparator;

    public MinStack(Comparator<E> comparator) 
    {
        this.comparator = comparator;
    }

    /**
     * Pushes an element onto the stack.
     *
     *
     * @param e the element to push
     */
    public void push(E e) {
        mainStack.push(e);
        if(minStack.isEmpty())
        {
            minStack.push(e);
        }
        else if(comparator.compare(e, minStack.peek())<=0)
        {
            minStack.push(e);
        }
        else
        {
            minStack.push(minStack.peek());
        }
    }

    /**
     * Pops an element from the stack.
     *
     *
     * @throws NoSuchElementException if this stack is empty
     */
    public E pop() {
       minStack.pop();
       return  mainStack.pop();
    }

    /**
     * Returns but not remove smallest element from the stack. Return null if stack is empty.
     *
     */
    public E getMinimum()
    {
        return minStack.peek();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Main stack{");
        for (E e : mainStack) {         
            sb.append(e.toString()).append(",");
        }
        sb.append("}");

        sb.append(" Min stack{");
        for (E e : minStack) {          
            sb.append(e.toString()).append(",");
        }
        sb.append("}");

        sb.append(" Minimum = ").append(getMinimum());
        return sb.toString();
    }

    public static void main(String[] args) {
        MinStack<Integer> st = new MinStack<Integer>(Comparators.INTEGERS);

        st.push(2);
        Assert.assertTrue("2 is min in stack {2}", st.getMinimum().equals(2));
        System.out.println(st);

        st.push(6);
        Assert.assertTrue("2 is min in stack {2,6}", st.getMinimum().equals(2));
        System.out.println(st);

        st.push(4);
        Assert.assertTrue("2 is min in stack {2,6,4}", st.getMinimum().equals(2));
        System.out.println(st);

        st.push(1);
        Assert.assertTrue("1 is min in stack {2,6,4,1}", st.getMinimum().equals(1));
        System.out.println(st);

        st.push(5);
        Assert.assertTrue("1 is min in stack {2,6,4,1,5}", st.getMinimum().equals(1));
        System.out.println(st);

        st.pop();
        Assert.assertTrue("1 is min in stack {2,6,4,1}", st.getMinimum().equals(1));
        System.out.println(st);

        st.pop();
        Assert.assertTrue("2 is min in stack {2,6,4}", st.getMinimum().equals(2));
        System.out.println(st);

        st.pop();
        Assert.assertTrue("2 is min in stack {2,6}", st.getMinimum().equals(2));
        System.out.println(st);

        st.pop();
        Assert.assertTrue("2 is min in stack {2}", st.getMinimum().equals(2));
        System.out.println(st);

        st.pop();
        Assert.assertTrue("null is min in stack {}", st.getMinimum()==null);
        System.out.println(st);
    }
}

0
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Solution 
{
    public class MinStack
    {
        public MinStack()
        {
            MainStack=new Stack<int>();
            Min=new Stack<int>();
        }

        static Stack<int> MainStack;
        static Stack<int> Min;

        public void Push(int item)
        {
            MainStack.Push(item);

            if(Min.Count==0 || item<Min.Peek())
                Min.Push(item);
        }

        public void Pop()
        {
            if(Min.Peek()==MainStack.Peek())
                Min.Pop();
            MainStack.Pop();
        }
        public int Peek()
        {
            return MainStack.Peek();
        }

        public int GetMin()
        {
            if(Min.Count==0)
                throw new System.InvalidOperationException("Stack Empty"); 
            return Min.Peek();
        }
    }
}

0

Znalazłem tutaj świetne rozwiązanie: https://www.geeksforgeeks.org/design-a-stack-that-supports-getmin-in-o1-time-and-o1-extra-space/

Poniżej znajduje się kod Pythona, który napisałem zgodnie z algorytmem:

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

class MinStack:
    def __init__(self):
        self.head = None
        self.min = float('inf')

    # @param x, an integer
    def push(self, x):
        if self.head == None:
            self.head = Node(x)
            self.min = x
        else:
            if x >= self.min:
                n = Node(x)
                n.next = self.head
                self.head = n
            else:
                v = 2 * x - self.min
                n = Node(v)
                n.next = self.head
                self.head = n
                self.min = x

    # @return nothing
    def pop(self):
        if self.head:
            if self.head.value < self.min:
                self.min = self.min * 2 - self.head.value
            self.head = self.head.next

    # @return an integer
    def top(self):
        if self.head:
            if self.head.value < self.min:
                self.min = self.min * 2 - self.head.value
                return self.min
            else:
                return self.head.value
        else:
            return -1

    # @return an integer
    def getMin(self):
        if self.head:
            return self.min
        else:
            return -1

0

Aby pobraćMin elementów ze stosu. Musimy użyć Two stack .ie Stack s1 i Stack s2.

  1. Początkowo oba stosy są puste, więc dodaj elementy do obu stosów

--------------------- Wywołaj rekurencyjnie krok 2 do 4 -----------------------

  1. if Nowy element dodany do stosu s1, a następnie zdejmij elementy ze stosu s2

  2. porównaj nowe elementy z s2. który jest mniejszy, przesuń do s2.

  3. pop ze stosu s2 (który zawiera min element)

Kod wygląda następująco:

package Stack;
import java.util.Stack;
public class  getMin 
{  

        Stack<Integer> s1= new Stack<Integer>();
        Stack<Integer> s2 = new Stack<Integer>();

        void push(int x)
        {
            if(s1.isEmpty() || s2.isEmpty())

            {
                 s1.push(x);
                 s2.push(x);
            }
            else
            {

               s1. push(x);
                int y = (Integer) s2.pop();
                s2.push(y);
                if(x < y)
                    s2.push(x);
                        }
        }
        public Integer pop()
        {
            int x;
            x=(Integer) s1.pop();
            s2.pop();
            return x;

        }
    public  int getmin()
        {
            int x1;
            x1= (Integer)s2.pop();
            s2.push(x1);
            return x1;
        }

    public static void main(String[] args) {
        getMin s = new getMin();
            s.push(10);
            s.push(20);
            s.push(30);
            System.out.println(s.getmin());
            s.push(1);
            System.out.println(s.getmin());
        }

}

-1

Myślę, że tylko operacja wypychania cierpi, wystarczy. Moja implementacja zawiera stos węzłów. Każdy węzeł zawiera element danych, a także minimum w tym momencie. To minimum jest aktualizowane za każdym razem, gdy wykonywana jest operacja wypychania.

Oto kilka punktów do zrozumienia:

  • Zaimplementowałem stos używając listy połączonej.

  • Górna część wskaźnika zawsze wskazuje na ostatni wypchnięty element. Kiedy na tym stosie nie ma żadnego elementu, jest to NULL.

  • Kiedy element jest wypychany, przydzielany jest nowy węzeł, który ma następny wskaźnik wskazujący na poprzedni stos, a wierzchołek jest aktualizowany tak, aby wskazywał na ten nowy węzeł.

Jedyną różnicą w stosunku do normalnej implementacji stosu jest to, że podczas wypychania aktualizuje on min członka dla nowego węzła.

Proszę spojrzeć na kod, który został zaimplementowany w C ++ w celach demonstracyjnych.

/*
 *  Implementation of Stack that can give minimum in O(1) time all the time
 *  This solution uses same data structure for minimum variable, it could be implemented using pointers but that will be more space consuming
 */

#include <iostream>
using namespace std;

typedef struct stackLLNodeType stackLLNode;

struct stackLLNodeType {
    int item;
    int min;
    stackLLNode *next;
};

class DynamicStack {
private:
    int stackSize;
    stackLLNode *top;

public:
    DynamicStack();
    ~DynamicStack();
    void push(int x);
    int pop();
    int getMin();
    int size() { return stackSize; }
};

void pushOperation(DynamicStack& p_stackObj, int item);
void popOperation(DynamicStack& p_stackObj);

int main () {
    DynamicStack stackObj;

    pushOperation(stackObj, 3);
    pushOperation(stackObj, 1);
    pushOperation(stackObj, 2);
    popOperation(stackObj);
    popOperation(stackObj);
    popOperation(stackObj);
    popOperation(stackObj);
    pushOperation(stackObj, 4);
    pushOperation(stackObj, 7);
    pushOperation(stackObj, 6);
    popOperation(stackObj);
    popOperation(stackObj);
    popOperation(stackObj);
    popOperation(stackObj);

    return 0;
}

DynamicStack::DynamicStack() {
    // initialization
    stackSize = 0;
    top = NULL;
}

DynamicStack::~DynamicStack() {
    stackLLNode* tmp;
    // chain memory deallocation to avoid memory leak
    while (top) {
        tmp = top;
        top = top->next;
        delete tmp;
    }
}

void DynamicStack::push(int x) {
    // allocate memory for new node assign to top
    if (top==NULL) {
        top = new stackLLNode;
        top->item = x;
        top->next = NULL;
        top->min = top->item;
    }
    else {
        // allocation of memory
        stackLLNode *tmp = new stackLLNode;
        // assign the new item
        tmp->item = x;
        tmp->next = top;

        // store the minimum so that it does not get lost after pop operation of later minimum
        if (x < top->min)
            tmp->min = x;
        else
            tmp->min = top->min;

        // update top to new node
        top = tmp;
    }
    stackSize++;
}

int DynamicStack::pop() {
    // check if stack is empty
    if (top == NULL)
        return -1;

    stackLLNode* tmp = top;
    int curItem = top->item;
    top = top->next;
    delete tmp;
    stackSize--;
    return curItem;
}

int DynamicStack::getMin() {
    if (top == NULL)
        return -1;
    return top->min;
}
void pushOperation(DynamicStack& p_stackObj, int item) {
    cout<<"Just pushed: "<<item<<endl;
    p_stackObj.push(item);
    cout<<"Current stack min: "<<p_stackObj.getMin()<<endl;
    cout<<"Current stack size: "<<p_stackObj.size()<<endl<<endl;
}

void popOperation(DynamicStack& p_stackObj) {
    int popItem = -1;
    if ((popItem = p_stackObj.pop()) == -1 )
        cout<<"Cannot pop. Stack is empty."<<endl;
    else {
        cout<<"Just popped: "<<popItem<<endl;
        if (p_stackObj.getMin() == -1)
            cout<<"No minimum. Stack is empty."<<endl;
        else
            cout<<"Current stack min: "<<p_stackObj.getMin()<<endl;
        cout<<"Current stack size: "<<p_stackObj.size()<<endl<<endl;
    }
}

A wynik programu wygląda następująco:

Just pushed: 3
Current stack min: 3
Current stack size: 1

Just pushed: 1
Current stack min: 1
Current stack size: 2

Just pushed: 2
Current stack min: 1
Current stack size: 3

Just popped: 2
Current stack min: 1
Current stack size: 2

Just popped: 1
Current stack min: 3
Current stack size: 1

Just popped: 3
No minimum. Stack is empty.
Current stack size: 0

Cannot pop. Stack is empty.
Just pushed: 4
Current stack min: 4
Current stack size: 1

Just pushed: 7
Current stack min: 4
Current stack size: 2

Just pushed: 6
Current stack min: 4
Current stack size: 3

Just popped: 6
Current stack min: 4
Current stack size: 2

Just popped: 7
Current stack min: 4
Current stack size: 1

Just popped: 4
No minimum. Stack is empty.
Current stack size: 0

Cannot pop. Stack is empty.

-1
public interface IMinStack<T extends Comparable<T>> {
  public void push(T val);
  public T pop();
  public T minValue();
  public int size();
}

import java.util.Stack;

public class MinStack<T extends Comparable<T>> implements IMinStack<T> {
  private Stack<T> stack = new Stack<T>();
  private Stack<T> minStack = new Stack<T>();

  @Override
  public void push(T val) {
    stack.push(val);
    if (minStack.isEmpty() || val.compareTo(minStack.peek()) < 0)
        minStack.push(val);
  }

  @Override
  public T pop() {
    T val = stack.pop();
    if ((false == minStack.isEmpty())
            && val.compareTo(minStack.peek()) == 0)
        minStack.pop();
    return val;
  }

  @Override
  public T minValue() {
    return minStack.peek();
  }

  @Override
  public int size() {
    return stack.size();
  }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.