getMinimum () O (1) olmalıdır gibi bir yığın tasarlayın


118

Bu bir röportaj sorusudur. GetMinimum () işlevinin yığındaki minimum öğeyi döndürmesini sağlayacak şekilde bir tamsayı değeri tutan bir yığın tasarlamanız gerekir.

Örneğin: aşağıdaki örneği düşünün

dava 1

5 -> ÜST
1
4
6
2

GetMinimum () çağrıldığında, minimum eleman olan 1 döndürmelidir 
yığında. 

vaka # 2

) (Stack.pop
) (Stack.pop

Not: Hem 5 hem de 1 yığından çıkarılır. Yani bundan sonra yığın
gibi görünüyor

4 -> ÜST
6
2

GetMinimum () çağrıldığında, en düşük değer olan 2 döndürmelidir 
yığını.

Constriants:

  1. getMinimum, O (1) 'deki minimum değeri döndürmelidir
  2. Alan kısıtlaması da tasarlanırken göz önünde bulundurulmalı ve eğer fazladan alan kullanırsanız, sabit alan olmalıdır.

Yanıtlar:


180

DÜZENLEME: Bu, "sabit alan" kısıtlamasını geçersiz kılar - temelde gereken alanı iki katına çıkarır. Çalışma zamanı karmaşıklığını bir yerde mahvetmeden bunu yapmayan bir çözüm olduğundan çok şüpheliyim (örneğin, push / pop O (n) yapmak). Bunun gerekli alanın karmaşıklığını değiştirmediğini unutmayın , örneğin, O (n) alan gereksinimleri olan bir yığınız varsa, bu yine de farklı bir sabit faktörle O (n) olacaktır.

Sabit olmayan alan çözümü

"Yığın içindeki tüm değerlerin minimum" altından "yinelenen" bir yığın tutun. Ana yığını açtığınızda, minimum yığını da açın. Ana yığını ittiğinizde, hangisi daha düşükse, yeni elemanı veya mevcut min değerini itin. getMinimum()daha sonra adil olarak uygulanır minStack.peek().

Yani örneğinizi kullanarak, bizde:

Real stack        Min stack

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

İki kez patladıktan sonra şunları elde edersiniz:

Real stack        Min stack

4                 2
6                 2
2                 2

Bu yeterli bilgi değilse lütfen bana bildirin. Salladığınızda basit, ama ilk başta biraz kafa karıştırmak gerekebilir :)

(Elbette dezavantajı, alan gereksinimini iki katına çıkarmasıdır. Yürütme süresi önemli ölçüde etkilenmez - yani hala aynı karmaşıklıktır.)

DÜZENLEME: Biraz daha karmaşık, ancak genel olarak daha iyi alana sahip bir varyasyon var. Hala min yığınına sahibiz, ancak ondan yalnızca ana yığından çıkardığımız değer, min. Yığın üzerindekine eşit olduğunda çıkar. Sadece itme ana yığını daha az olduğu üzerine değeri itilen dakika yığınına eşit veya mevcut dakika değerine. Bu, yinelenen minimum değerlere izin verir. getMinimum()hala sadece bir gözetleme operasyonudur. Örneğin, orijinal sürümü alıp tekrar 1'e basarsak şunu elde ederiz:

Real stack        Min stack

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

1 == 1 olduğu için her iki yığıntan da yukarıdakilerden çıkan poplar:

Real stack        Min stack

5  --> TOP        1
1                 2
4                 
6                 
2                 

Tekrar patlatma sadece ana yığından çıkar, çünkü 5> 1:

Real stack        Min stack

1                 1
4                 2
6                 
2                 

1 == 1 olduğu için yeniden patlatma her iki yığını da çıkarır:

Real stack        Min stack

4                 2
6                 
2                 

Bu, aynı en kötü durum uzay karmaşıklığı (orijinal yığının iki katı), ancak nadiren "yeni bir minimum veya eşit" elde edersek çok daha iyi alan kullanımı ile sonuçlanır.

DÜZENLEME: İşte Pete'in şeytani planının bir uygulaması. İyice test etmedim ama bence sorun değil :)

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
Zeki! @Ganesh: Çalışma zamanı neden bir sorun olsun? Tek bir yığından yalnızca iki kat daha uzun sürer, yani push () ve pop () ve getMinimum () için hala O (1) zamanı - bu mükemmel bir performans!
j_random_hacker

4
Tek bir değişkeniniz varsa, örneğinizde "1" i açtığınızda ne olur? Önceki minimumun "2" olduğu anlaşılmalıdır - her şeyi taramadan yapamaz.
Jon Skeet

1
@Ganesh: O halde, () her açtığınızda bir O (n) araması kullanarak yeni minimum değeri bulmanız gerekmeyecek mi?
j_random_hacker

2
Sadece diğer yorumlarınızı okurken, "yığın tasarımının kendisinde" derken "her öğede" mi demek istiyorsunuz? Öyleyse, öğe türünün boyutuna bağlı olarak bellek gereksinimlerini potansiyel olarak neredeyse iki katına çıkarıyorsunuz demektir. Kavramsal olarak iki yığınla aynıdır.
Jon Skeet

1
@Ganesh: Maalesef fazladan yığın olmaması, yukarıda dahil ettiğim yerden tasarruf sağlayan optimizasyonu yapamayacağımız anlamına geliyor. "Minimum ve elemanı" bir arada tutmak, muhtemelen dile bağlı olsa da, aynı boyuttaki iki yığından (daha az ek yük - diziler, liste düğümleri vb.) Daha etkilidir.
Jon Skeet

41

Minimum değeri tutmak ve Pop () ve Push () sırasında güncellemek için bir alan ekleyin. Bu şekilde getMinimum () O (1) olacaktır, ancak Pop () ve Push () biraz daha iş yapmak zorunda kalacaktır.

Minimum değer atılırsa, Pop () O (n) olur, aksi takdirde ikisi de yine O (1) olur. Yeniden boyutlandırıldığında, Yığın uygulamasına göre Push () O (n) olur.

İşte hızlı bir uygulama

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

üzgünüm anlamadım neden pop () ve push () zarar görür?
Ganesh M

11
Pop () 'de, O (n) alan "yeni" minimum eleman bulunmalıdır. Bu işlem hala O (1) olduğundan, push () zarar görmez.
Georg Schölly

4
@sigjuice: doğru. Sanırım "acı" kelimesini daha az dramatik bir şeye çevireceğim :)
Brian Rasmussen

2
@Ganesh M "eleman toplama alanı", N elemanınızda ek bir alan varsa, bu sabit alan değil, O (N) fazladır.
Pete Kirkham

1
Bir işlem sırasında minimum değer yığından çıkarılırsa, bir sonraki minimum değer nasıl bulunur? Bu yöntem, bu senaryoyu desteklemiyor ...
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();
    }

}

Mevcut minimumu açıkça depolar ve minimum değişirse, değeri itmek yerine, yeni minimumun diğer tarafına aynı farkı ittirir (min = 7 ve 5'e basarsanız, onun yerine 3'e (5- | 7-5 | = 3) ve min'i 5 olarak ayarlar; eğer min 5 olduğunda 3'ü atarsanız, atılan değerin min'den küçük olduğunu görür, bu nedenle yeni min için 7 elde etmek için prosedürü tersine çevirir, ardından öncekini döndürür dakika). Mevcut minimumda bir değişikliğe neden olmayan herhangi bir değer mevcut minimum değerden daha büyük olduğundan, minimumu değiştiren ve değiştirmeyen değerler arasında ayrım yapmak için kullanılabilecek bir şeye sahipsiniz.

Sabit boyutlu tamsayılar kullanan dillerde, değerlerin gösteriminden biraz alan ödünç alıyorsunuz, bu nedenle yetersiz kalabilir ve iddia başarısız olur. Ancak aksi takdirde, sabit fazladan boşluktur ve tüm işlemler hala O (1) 'dir.

Bunun yerine bağlantılı listeleri temel alan yığınlar, bir miktar ödünç alabileceğiniz başka yerlere sahiptir, örneğin bir sonraki işaretçinin en önemsiz biti C veya Java'da bağlantılı listedeki nesnelerin türü. Java için bu, bağlantı başına nesne ek yüküne sahip olduğunuzdan, bitişik bir yığına kıyasla daha fazla alan kullanıldığı anlamına gelir:

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

C'de ek yük yoktur ve bir sonraki işaretçinin lsb'sini ödünç alabilirsiniz:

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

Ancak, bunların hiçbiri gerçekten O (1) değildir. Pratikte daha fazla alana ihtiyaç duymazlar, çünkü bu dillerdeki sayıların, nesnelerin veya işaretçilerin temsillerindeki boşlukları kullanırlar. Ancak daha kompakt bir gösterim kullanan teorik bir makine, her durumda bu gösterime fazladan bir bit eklenmesini gerektirecektir.


+1 gerçekten çok zarif ... ideone'da çalışan önemsiz bir şekilde taşınan C ++ sürümü . Şerefe.
Tony Delroy

Java'da, bu pop(), son itilen değer olması durumunda yanlış sonuç üretecektir Integer.MIN_VALUE(örn. İtme 1, Tamsayı.MIN_VALUE, pop). Bu, yukarıda belirtildiği gibi alttan taşmadan kaynaklanmaktadır. Aksi takdirde tüm tamsayı değerleri için çalışır.
Theo

13

Bahsedilen tüm kısıtlamaları (sabit zamanlı işlemler) ve sabit ekstra alanı karşılayan bir çözüm buldum .

Fikir, minimum değer ile giriş numarası arasındaki farkı saklamak ve artık minimum değilse minimum değeri güncellemektir.

Kod aşağıdaki gibidir:

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

Kredi şu adrese gider: https://leetcode.com/discuss/15679/share-my-java-solution-with-only-one-stack


Bu çalışıyor. Yığındaki negatif sayılarla da denedim. Ve hatırlanacak kadar da basit. Teşekkürler.
r9891

7

Peki, çalışma zamanı kısıtlamaları nelerdir pushve pop? Sabit olmaları gerekmiyorsa, bu iki işlemdeki minimum değeri hesaplayın (onları O ( n ) yaparak ). Aksi takdirde, bunun sabit ek alanla nasıl yapılabileceğini anlamıyorum.


4
+1, hehe ... Eski "kuralları bükme" hilesi ... Benzer şekilde, herhangi bir boyut dizisini O (1) zamanında sıralayan bir sıralama algoritması biliyorum, ancak sonuç O (nlog n) ek yüke maruz
kalıyor

3
Haskell'de her şey sabit zamandır! (sonucu yazdırmak istemeniz dışında)
Henk

1
Zayıf problem spesifikasyonuna dikkat çekmek için +1. "Bunun nasıl yapılacağını anlamıyorum" - ben de yapmadım, ama Pete Kirkham'ın çözümü bunu çok zarif bir şekilde yapıyor ....
Tony Delroy

1

İşte O (1) ile çalışan Kodum. Gönderdiğim önceki kod, minimum eleman atıldığında sorun yaşadı. Kodumu değiştirdim. Bu, mevcut itilen öğenin üzerindeki yığında bulunan minimum öğeyi tutan başka bir Yığın kullanır.

 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
Lütfen burada kod yazmak için kullanılan programlama dilini belirtin. Potansiyel ziyaretçilerin söz dizimine göre neyin olup bittiğini anlamasına yardımcı olur. C # olduğunu varsayıyorum ama ya birisi yapmazsa?
realPK

1

Farklı bir yığın kullandım. İşte uygulama.

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

Çıktı:

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

Dene. Sanırım soruyu yanıtlıyor. Her çiftin ikinci öğesi, o öğe eklendiğinde görülen minimum değeri verir.


1

Belirli bir yığında minimum ve maksimum değeri bulmak için kodun tamamını buraya gönderiyorum.

Zaman karmaşıklığı O (1) olacaktır ..

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

Herhangi bir sorunla karşılaşırsanız bana bildirin

Teşekkürler, Vikash


1

Orijinal yığın sınıfınızı genişletebilir ve sadece minimum izlemeyi ekleyebilirsiniz. Orijinal ebeveyn sınıfının her şeyi her zamanki gibi halletmesine izin verin.

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

Bu çözüm aynı zamanda Stack <Integer> min.
Arpit

1

İşte java'daki çözümüm beğenilenler listesi.

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

Üzerinde çalışacağımız yığının şu olduğunu varsayalım:

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

Yukarıdaki gösterimde, yığın yalnızca sol değer tarafından oluşturulur, sağ değerin [minvalue] yalnızca bir değişkende saklanacak örnekleme amacıyla yazılır.

Asıl Sorun, minimum değer olan değerin bu noktada kaldırıldığı zamandır, yığın üzerinde yinelemeden bir sonraki minimum öğenin ne olduğunu nasıl bilebiliriz.

Örneğin yığınımızdaki 6 get atıldığında bunun minimum eleman olmadığını biliyoruz çünkü minimum eleman 2'dir, bu yüzden bunu minimum değerimizi güncellemeden güvenle kaldırabiliriz.

Ancak 2'yi açtığımızda, şu anda minimum değerin 2 olduğunu görebiliriz ve bu ortaya çıkarsa minimum değeri 3 olarak güncellememiz gerekir.

1. Nokta:

Şimdi dikkatlice gözlemlerseniz, bu belirli durumdan [2, minvalue = 2] minvalue = 3 üretmemiz gerekir. ya da yığın depperine giderseniz, bu belirli durumdan [3, minvalue = 3] minvalue = 7 oluşturmamız gerekir ya da yığın içinde daha depper giderseniz, bu belirli durumdan [7, minvalue] minvalue = 8 oluşturmamız gerekir = 7]

Yukarıdaki 3 durumun hepsinde ortak bir şey fark ettiniz mi, üretmemiz gereken değer, her ikisi de eşit olan iki değişkene bağlıdır. Doğru. Bu neden oluyor çünkü bazı elementleri mevcut minvalue'dan daha küçük ittiğimizde, temelde o elementi yığına itiyoruz ve aynı sayıyı minvalue'da da güncelliyoruz.

Nokta2'ye:

Yani temelde aynı sayının bir kopyasını bir yığınta ve bir kez de minvalue değişkeninde depoluyoruz. Bu yinelemeden kaçınmaya odaklanmalıyız ve yukarıdaki CASES'te gösterildiği gibi önceki minimum değeri oluşturmak için yığında veya minvalue'da yararlı bir şeyler depolamalıyız.

Push'da depolanacak değer minmumvalue'dan daha az olduğunda yığında neyi depolamamız gerektiğine odaklanalım. Bu değişkeni y olarak adlandıralım, şimdi yığımız şöyle görünecek:

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

Hepsinin aynı değere sahip olacağına dair karışıklığı önlemek için onları y1, y2, y3 olarak yeniden adlandırdım.

Point3:

Şimdi y1, y2 ve y3 üzerinde bazı kısıtlamalar bulmaya çalışalım. Pop () yaparken minvalue'yu tam olarak ne zaman güncellememiz gerektiğini hatırlıyor musunuz, sadece minvalue'a eşit olan elementi açtığımızda. Minvalue'dan daha büyük bir şey açarsak, minvalue'yu güncellememiz gerekmez. Dolayısıyla, minvalue güncellemesini tetiklemek için, y1, y2 ve y3 oradaki minvalue'dan daha küçük olmalıdır. [[Point2]] 'nin yinelenmesini önlemek için eşitlikten kaçınıyoruz, bu nedenle kısıt [y <minValue].

Şimdi y'yi doldurmak için geri dönelim, itme anında bir değer üretmeli ve y koymalıyız, unutmayın. İtme için gelen değeri x, yani prevMinvalue'dan daha az ve aslında yığında iteceğimiz değeri y olarak alalım. Bir şey açıktır ki, newMinValue = x ve y <newMinvalue.

Şimdi prevMinvalue ve x (newMinvalue) yardımıyla y'yi hesaplamamız gerekiyor (y'nin newMinValue (x) 'den daha küçük bir sayı olabileceğini hatırlayın, bu yüzden bizim kısıtımızı karşılayabilecek bir sayı bulmamız gerekiyor).

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].

Dolayısıyla, x'i itme anında, eğer prevMinvalue'dan küçükse, o zaman y [2 * x-prevMinValue] 'a göndeririz ve newMinValue = x'i güncelleriz.

Ve pop anında eğer yığın minValue'dan daha az bir şey içeriyorsa, o zaman minVAlue'yu güncellemek için tetikleyicimiz budur. CurMinValue ve y'den prevMinValue'yu hesaplamamız gerekiyor. y = 2 * curMinValue - prevMinValue [Kanıtlanmış] prevMinVAlue = 2 * curMinvalue - y.

2 * curMinValue - y, prevMinValue'a şimdi güncellememiz gereken sayıdır.

Aynı mantık için kod aşağıda O (1) zamanı ve O (1) uzay karmaşıklığı ile paylaşılmıştır.

// 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

İşte benim uygulama versiyonum.

 struct MyStack {
    int öğesi;
    int * CurrentMiniAddress;
 };

 void Push (int değeri)
 {
    // Yapınızı oluşturun ve değeri doldurun
    MyStack S = yeni MyStack ();
    S-> eleman = değer;

    Eğer (Stack.Empty ())
    {    
        // Yığın boş olduğundan, CurrentMiniAddress'i kendisine işaret edin
        S-> CurrentMiniAddress = S;

    }
    Başka
    {
         // Yığın boş değil

         // En üstteki öğeyi alın. Pop Yok ()
         MyStack * TopElement = Stack.Top ();

         // Her zaman TOP öğesinin
         // tüm yığındaki minimum öğe
         if (S-> element CurrentMiniAddress-> element)
         {
            // Mevcut değer tüm yığındaki minimum ise
            // sonra S kendini gösterir
            S-> CurrentMiniAddress = S;
         }
             Başka
             {
                 // Yani bu, tüm yığındaki minimum değil
                 // Endişelenmeyin, TOP minimum öğeyi tutuyor
                 S-> CurrentMiniAddress = TopElement-> CurrentMiniAddress;
             }

    }
        Stack.Add (S);
 }

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

 int GetMinimum (Yığın ve yığın)
 {
       if (! stack.Empty ())
       {
            MyStack * Top = stack.top ();
            // Üst her zaman minimumx'i gösterir
            Return Top-> CurrentMiniAddress-> element;
        }
 }

Kabul Ediyorum, bu yapınızda ek bir unsur gerektirir. Ancak bu, bir öğeyi ne zaman açsak minimum bulmayı ortadan kaldırır.
Ganesh M

1
Öyleyse, sorunun kısıtlamalarını karşılayamadığınız için işi kaptınız mı?
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

Bu çözümü burada buldum

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

İşte O (1) ile çalışan Kodum. Burada itilen değeri içeren ve ayrıca bu itilen değere kadar minimum değeri içeren vektör çiftini kullandım.


İşte benim C ++ uygulama sürümüm.

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 */

Bu, Jon Skeet'in cevabına ne katıyor ? Bu, sonsuza doğru n için ne kadar boşluk kullanır (soruya veya bağlantılı cevaba bakın)? OO'yu desteklediğini iddia eden bir programlama dili ile, (çok soyut olmayan) bir veri türü / (jenerik) Class- MinStack? Oluşturmak daha uygun görünmektedir. Oracle'ın Java belgeleri kullanmanızı tavsiye eder Deque.
greybeard

(İpuçları aldığınız için teşekkürler. (Kod yorumları neyin, nasıl ve niçin olduğunu açıklamalıdır - bir koşulun bir koşul olduğunu belirtmek yardımcı olmaz. İlk bir veya iki satırın girintili olmaması daha iyidir, elde edilir, mevcut, burada , küçültülmüş ve genişletilmiş …))
greybeard

0

Okul adlı bir Kullanıcı Tarafından Tasarlanmış Nesne Yığınında minimum bulmak için pratik bir uygulama

Yığın, Okulları Stack'te belirli bir bölgedeki bir okula atanan sıralamaya göre depolayacak, diyelim ki findMin (), Kabul için maksimum başvuru sayısını aldığımız Okulu verir, bu da sırayla tanımlanacaktır. önceki sezondaki okullarla ilişkili sıralamayı kullanan karşılaştırıcı.

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

}

Ayrıca Okul Nesnesi aşağıdaki gibidir:

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

}

Bu Örnek aşağıdakileri kapsar: 1. Kullanıcı tanımlı Nesneler için Yığın Uygulanması, burada, Okul 2. Karşılaştırılacak tüm Nesnelerin alanlarını kullanarak hashcode () ve equals () yönteminin uygulanması 3. Senaryo için pratik bir uygulama rqeuire, Yığın işleminin O (1) sırasına göre olmasını sağlar


Bu soruda dil etiketi yok (tam tersine :): language-agnosticlütfen kod için ne kullandığınızı belirtin (ve daha önce boşlukları kaldırın The Code for same is below:.) Bu nasıl desteklenir stack.pop()? (ve push()?)
greybeard

0

İşte Jon Skeet'in cevabında O (1) 'de maksimum yığın elde etmek için biraz daha iyi alan karmaşıklığı uygulaması olarak açıklanan şeyin PHP uygulaması .

<?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

İşte Jon Skeets ait C ++ uygulamasıdır Yanıt . Bunu uygulamanın en uygun yolu olmayabilir, ancak tam olarak yapması gerekeni yapar.

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

Ve işte sınıfın sürücüsü

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

Çıktı:

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

0

Biz yapabilirsiniz O (n) zaman ve O bunu (1) uzay karmaşıklığı, şöyle:

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

Yığın uygulamanızda bir LinkedList kullanabileceğinizi düşünüyorum.

İlk kez bir değer ittiğinde, bu değeri bağlantılı liste başı olarak koyarsın.

daha sonra bir değere her bastığınızda, <head.data yeni değeri bir prepand işlemi yaparsa (bu, başın yeni değer olduğu anlamına gelir)

değilse, bir ekleme işlemi yapın.

Bir pop () oluşturduğunuzda, min == linkedlist.head.data olup olmadığını, evet ise head = head.next;

İşte kodum.

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

}

 }

Bir dizi numaraya sahip olun. Bir döngüde, sayı çift ise, iki öğe açılır. Numarayı itin ve minimum değeri yazdırın.
greybeard


En üst değerin == 0 olup olmadığını kontrol etmek için pop () yöntemini ayarlayabiliriz, eğer öyleyse, bağlantılı listeyi 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

Burada mükemmel bir çözüm gördü: https://www.geeksforgeeks.org/design-a-stack-that-supports-getmin-in-o1-time-and-o1-extra-space/

Körük, algoritmayı takip ederek yazdığım python kodudur:

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

Stack'den Min öğelerini almak için. Two stack .ie Stack s1 ve Stack s2 kullanmalıyız.

  1. Başlangıçta, her iki yığın da boş olduğundan, her iki yığına da öğeler ekleyin

--------------------- Adım 2 ila 4'ü yinelemeli olarak çağırın -----------------------

  1. s1 yığınına yeni eleman eklenirse, s2 yığınından eleman çıkar

  2. Yeni seçimleri s2 ile karşılaştırır. hangisi daha küçükse, s2'ye basın.

  3. yığın s2'den pop (minimum eleman içerir)

Kod şöyle görünür:

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

Bence sadece itme işlemi acı çekiyor, yeterli. Benim uygulamam bir yığın düğüm içeriyor. Her düğüm, veri öğesini ve aynı zamanda o andaki minimumunu içerir. Bu minimum, bir itme işlemi her yapıldığında güncellenir.

İşte anlamak için bazı noktalar:

  • Yığını Linked List kullanarak uyguladım.

  • Üstteki bir işaretçi her zaman en son itilen öğeyi gösterir. Bu yığında hiç öğe olmadığında üst NULL olur.

  • Bir öğe itildiğinde, önceki yığını gösteren bir sonraki işaretçiye sahip yeni bir düğüm atanır ve top bu yeni düğümü işaret edecek şekilde güncellenir.

Normal yığın uygulamasındaki tek fark, push sırasında yeni düğüm için bir üye min.

Lütfen gösteri amacıyla C ++ 'da uygulanan koda bir göz atın.

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

Ve programın çıktısı şuna benzer:

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();
  }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.