desain tumpukan sedemikian rupa sehingga getMinimum () harus O (1)


118

Ini adalah salah satu pertanyaan wawancara. Anda perlu mendesain tumpukan yang menyimpan nilai integer sehingga fungsi getMinimum () harus mengembalikan elemen minimum dalam tumpukan.

Misalnya: perhatikan contoh di bawah ini

kasus 1

5 -> ATAS
1
4
6
2

Ketika getMinimum () dipanggil, ia harus mengembalikan 1, yang merupakan elemen minimum 
di tumpukan. 

kasus # 2

stack.pop ()
stack.pop ()

Catatan: 5 dan 1 keduanya muncul dari tumpukan. Jadi setelah ini, tumpukan
seperti,

4 -> ATAS
6
2

Ketika getMinimum () dipanggil harus mengembalikan 2 yang merupakan minimum di 
tumpukan.

Constriants:

  1. getMinimum harus mengembalikan nilai minimum dalam O (1)
  2. Batasan ruang juga harus dipertimbangkan saat mendesainnya dan jika Anda menggunakan ruang ekstra, ruang itu harus konstan.

Jawaban:


180

EDIT: Ini gagal dalam batasan "ruang konstan" - pada dasarnya menggandakan ruang yang diperlukan. Saya sangat meragukan bahwa ada solusi yang tidak melakukan itu, tanpa merusak kompleksitas runtime di suatu tempat (misalnya membuat push / pop O (n)). Perhatikan bahwa ini tidak mengubah kompleksitas ruang yang diperlukan, misalnya jika Anda memiliki tumpukan dengan persyaratan ruang O (n), ini akan tetap menjadi O (n) hanya dengan faktor konstanta yang berbeda.

Solusi ruang non-konstan

Jaga agar tumpukan "duplikat" dari "minimal semua nilai lebih rendah dalam tumpukan". Saat Anda meletuskan tumpukan utama, keluarkan juga tumpukan min. Saat Anda mendorong tumpukan utama, dorong elemen baru atau min saat ini, mana saja yang lebih rendah. getMinimum()kemudian diimplementasikan sebagai adil minStack.peek().

Jadi dengan menggunakan contoh Anda, kami memiliki:

Real stack        Min stack

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

Setelah muncul dua kali Anda mendapatkan:

Real stack        Min stack

4                 2
6                 2
2                 2

Tolong beri tahu saya jika informasi ini tidak cukup. Sederhana saja ketika Anda mengelusnya, tetapi mungkin akan sedikit menggaruk-garuk kepala pada awalnya :)

(Kelemahannya tentu saja adalah bahwa hal itu menggandakan kebutuhan ruang. Waktu eksekusi tidak terpengaruh secara signifikan - yaitu masih kompleksitas yang sama.)

EDIT: Ada variasi yang sedikit lebih rumit, tetapi memiliki ruang yang lebih baik secara umum. Kami masih memiliki tumpukan min, tetapi kami hanya muncul darinya ketika nilai yang kami keluarkan dari tumpukan utama sama dengan yang ada di tumpukan min. Kami hanya mendorong ke tumpukan minimum ketika nilai yang didorong ke tumpukan utama kurang dari atau sama dengan nilai min saat ini. Ini memungkinkan duplikat nilai min. getMinimum()masih hanya operasi intip. Misalnya, mengambil versi asli dan mendorong 1 lagi, kita akan mendapatkan:

Real stack        Min stack

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

Muncul dari atas muncul dari kedua tumpukan karena 1 == 1, meninggalkan:

Real stack        Min stack

5  --> TOP        1
1                 2
4                 
6                 
2                 

Muncul lagi hanya muncul dari tumpukan utama, karena 5> 1:

Real stack        Min stack

1                 1
4                 2
6                 
2                 

Muncul lagi memunculkan kedua tumpukan karena 1 == 1:

Real stack        Min stack

4                 2
6                 
2                 

Ini berakhir dengan kompleksitas ruang kasus terburuk yang sama (menggandakan tumpukan asli) tetapi penggunaan ruang yang jauh lebih baik jika kita jarang mendapatkan "minimum baru atau sama".

EDIT: Berikut implementasi skema jahat Pete. Saya belum mengujinya secara menyeluruh, tapi menurut saya tidak apa-apa :)

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
Pintar! @Ganesh: Mengapa runtime menjadi masalah? Ini hanya akan memakan waktu dua kali lebih lama dari satu tumpukan, yaitu masih O (1) waktu untuk push () dan pop () serta untuk getMinimum () - itu adalah kinerja yang luar biasa!
j_random_hacker

4
Jika Anda memiliki variabel tunggal, apa yang terjadi jika Anda memasukkan "1" dalam contoh Anda? Harus dipastikan bahwa nilai minimum sebelumnya adalah "2" - yang tidak dapat dilakukan tanpa memindai semuanya.
Jon Skeet

1
@Ganesh: Tidakkah Anda kemudian perlu menemukan minimum baru menggunakan pencarian O (n) setiap kali Anda pop ()?
j_random_hacker

2
Hanya membaca komentar Anda yang lain, saat Anda mengatakan "dalam desain tumpukan itu sendiri" yang Anda maksudkan "dalam setiap elemen"? Jika demikian, Anda masih berpotensi menggandakan persyaratan memori, bergantung pada ukuran jenis elemen. Secara konseptual sama dengan dua tumpukan.
Jon Skeet

1
@Ganesh: Sayangnya tidak memiliki tumpukan tambahan berarti kami tidak dapat melakukan pengoptimalan hemat ruang yang saya sertakan di atas. Menjaga "minimum dan elemen" bersama-sama mungkin lebih efisien daripada dua tumpukan dengan ukuran yang sama (lebih sedikit overhead - array, node daftar, dll) meskipun itu akan bergantung pada bahasa.
Jon Skeet

41

Tambahkan bidang untuk menampung nilai minimum dan perbarui selama Pop () dan Push (). Dengan cara itu getMinimum () akan menjadi O (1), tetapi Pop () dan Push () harus melakukan lebih banyak pekerjaan.

Jika nilai minimum muncul, Pop () akan menjadi O (n), jika tidak, keduanya akan tetap menjadi O (1). Saat mengubah ukuran Push () menjadi O (n) sesuai dengan implementasi Stack.

Berikut implementasi cepatnya

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

maaf saya tidak mengerti mengapa pop () dan push () akan menderita?
Ganesh M

11
Dalam pop () elemen minimum "baru" harus ditemukan, yang mengambil O (n). Push () tidak akan menderita, karena operasi ini masih O (1).
Georg Schölly

4
@sigjuice: benar. Saya pikir saya akan mengubah kata "menderita" menjadi sesuatu yang tidak terlalu dramatis :)
Brian Rasmussen

2
@Ganesh M "bidang penambahan elemen" jika Anda memiliki bidang tambahan di elemen N Anda, ini bukan ruang konstan, tetapi O (N) ekstra.
Pete Kirkham

1
Jika nilai minimum muncul dari tumpukan selama operasi, lalu bagaimana nilai minimum berikutnya ditemukan? Metode ini tidak mendukung skenario itu ...
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();
    }

}

Ini menyimpan minimum saat ini secara eksplisit, dan jika minimum berubah, alih-alih mendorong nilai, itu mendorong nilai perbedaan yang sama di sisi lain dari minimum baru (jika min = 7 dan Anda mendorong 5, itu mendorong 3 sebagai gantinya (5- | 7-5 | = 3) dan set min ke 5; jika Anda kemudian meletuskan 3 ketika min adalah 5, terlihat bahwa nilai yang muncul kurang dari min, jadi membalikkan prosedur untuk mendapatkan 7 untuk min baru, lalu mengembalikan yang sebelumnya min). Karena nilai apa pun yang tidak menyebabkan perubahan, minimum saat ini lebih besar dari minimum saat ini, Anda memiliki sesuatu yang dapat digunakan untuk membedakan antara nilai yang mengubah minimum dan yang tidak.

Dalam bahasa yang menggunakan bilangan bulat ukuran tetap, Anda meminjam sedikit ruang dari representasi nilai, sehingga mungkin kurang dan pernyataan akan gagal. Namun sebaliknya, ruang ekstra konstan dan semua operasi tetap O (1).

Tumpukan yang didasarkan pada daftar tertaut memiliki tempat lain yang dapat Anda pinjam sedikit, misalnya di C bit paling tidak signifikan dari penunjuk berikutnya, atau di Java, tipe objek dalam daftar tertaut. Untuk Java, ini berarti ada lebih banyak ruang yang digunakan dibandingkan dengan tumpukan yang berdekatan, karena Anda memiliki overhead objek per tautan:

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

Di C, overhead tidak ada, dan Anda dapat meminjam lsb dari pointer berikutnya:

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

Namun, tidak satupun dari ini benar-benar O (1). Mereka tidak memerlukan ruang lagi dalam praktiknya, karena mereka mengeksploitasi lubang dalam representasi angka, objek, atau penunjuk dalam bahasa ini. Tetapi mesin teoritis yang menggunakan representasi yang lebih kompak akan membutuhkan sedikit tambahan untuk ditambahkan ke representasi itu dalam setiap kasus.


+1 memang sangat elegan ... versi C ++ porting sepele yang berjalan di ideone di sini . Bersulang.
Tony Delroy

Di Java, ini akan menghasilkan hasil yang salah karena pop()jika nilai terakhir yang didorong adalah Integer.MIN_VALUE(misalnya, push 1, push Integer.MIN_VALUE, pop). Hal ini disebabkan karena kekurangan aliran listrik seperti yang disebutkan di atas. Jika tidak, berfungsi untuk semua nilai integer.
Theo

13

Saya menemukan solusi yang memenuhi semua batasan yang disebutkan (operasi waktu konstan) dan ruang ekstra konstan .

Idenya adalah untuk menyimpan selisih antara nilai min dan angka masukan, dan memperbarui nilai min jika tidak lagi minimum.

Kodenya adalah sebagai berikut:

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

Kredit diberikan ke: https://leetcode.com/discuss/15679/share-my-java-solution-with-only-one-stack


Yang ini berhasil. Saya mencoba dengan angka negatif di tumpukan juga. Dan cukup sederhana untuk diingat juga. Terima kasih.
r9891

7

Nah, apa saja batasan waktu proses pushdan pop? Jika mereka tidak harus konstan, maka hitung saja nilai minimum dalam dua operasi tersebut (menjadikannya O ( n )). Jika tidak, saya tidak melihat bagaimana ini bisa dilakukan dengan ruang tambahan yang konstan.


4
+1, hehe ... Trik lama "tekuk aturan" ... Dengan cara yang sama, saya tahu tentang algoritme penyortiran yang mengurutkan larik ukuran berapa pun dalam waktu O (1), tetapi akses pertama ke elemen apa pun dari Hasil menimbulkan O (nlog n) overhead ... :)
j_random_hacker

3
Di Haskell, semuanya adalah waktu yang konstan! (kecuali jika Anda ingin mencetak hasilnya)
Henk

1
1 untuk mencatat spesifikasi masalah yang buruk. "Saya tidak melihat bagaimana ini bisa dilakukan" - begitu pula saya, tetapi solusi Pete Kirkham melakukannya dengan sangat elegan ....
Tony Delroy

1

Ini Kode saya yang berjalan dengan O (1). Kode sebelumnya yang saya posting mengalami masalah ketika elemen minimum muncul. Saya mengubah kode saya. Yang ini menggunakan Tumpukan lain yang mempertahankan elemen minimum yang ada dalam tumpukan di atas elemen yang didorong saat ini.

 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
Sebutkan bahasa pemrograman yang digunakan di sini untuk menulis kode. Ini membantu calon pengunjung mengetahui apa yang terjadi berdasarkan sintaks. Saya menganggapnya C # tetapi bagaimana jika seseorang tidak?
realPK

1

Saya menggunakan jenis tumpukan yang berbeda. Berikut implementasinya.

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

Keluaran:

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

Cobalah. Saya pikir itu menjawab pertanyaan itu. Elemen kedua dari setiap pasangan memberikan nilai minimum yang terlihat saat elemen itu dimasukkan.


1

Saya memposting kode lengkap di sini untuk menemukan min dan max dalam tumpukan yang diberikan.

Kompleksitas waktu akan menjadi 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());
    }
}

Beri tahu saya jika Anda menghadapi masalah apa pun

Terima kasih, Vikash


1

Anda dapat memperluas kelas tumpukan asli Anda dan menambahkan pelacakan minimum ke dalamnya. Biarkan kelas induk asli menangani yang lainnya seperti biasa.

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

Solusi ini juga menggunakan ruang ekstra dalam hal Stack <Integer> min.
Arpit

1

Ini solusi saya di java menggunakan daftar suka.

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

Mari kita asumsikan tumpukan yang akan kita kerjakan adalah ini:

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

Pada representasi di atas stack hanya dibangun oleh nilai kiri [nilai min] nilai kanan ditulis hanya untuk tujuan ilustrasi yang akan disimpan dalam satu variabel.

Masalah sebenarnya adalah ketika nilai yang merupakan nilai minimum dihapus pada titik itu bagaimana kita bisa mengetahui apa elemen minimum berikutnya tanpa iterasi di atas tumpukan.

Seperti misalnya di tumpukan kami ketika 6 get muncul, kami tahu bahwa, ini bukan elemen minimum karena elemen minimumnya adalah 2, jadi kami dapat menghapus ini dengan aman tanpa memperbarui nilai min kami.

Tetapi ketika kita memunculkan 2, kita dapat melihat bahwa nilai minimumnya adalah 2 sekarang dan jika ini muncul maka kita perlu memperbarui nilai minimum menjadi 3.

Point1:

Sekarang jika Anda mengamati dengan seksama kita perlu menghasilkan nilai min = 3 dari keadaan tertentu ini [2, nilai minimum = 2]. atau jika Anda menggunakan tumpukan, kami perlu menghasilkan nilai minimum = 7 dari keadaan tertentu ini [3, nilai minimum = 3] atau jika Anda lebih depper dalam tumpukan maka kita perlu menghasilkan nilai minimum = 8 dari keadaan tertentu ini [7, nilai minimum = 7]

Apakah Anda melihat sesuatu yang sama dalam semua 3 kasus di atas, nilai yang perlu kita hasilkan bergantung pada dua variabel yang keduanya sama. Benar. Mengapa ini terjadi karena ketika kita mendorong beberapa elemen lebih kecil dari nilai min saat ini, maka pada dasarnya kita mendorong elemen itu ke dalam tumpukan dan memperbarui nomor yang sama di nilai min juga.

Point2:

Jadi pada dasarnya kita menyimpan duplikat dari nomor yang sama sekali dalam tumpukan dan sekali dalam variabel nilai kecil. Kita perlu fokus untuk menghindari duplikasi ini dan menyimpan data yang berguna dalam tumpukan atau nilai minimum untuk menghasilkan nilai minimum sebelumnya seperti yang ditunjukkan dalam KASUS di atas.

Mari kita fokus pada apa yang harus kita simpan dalam tumpukan ketika nilai yang akan disimpan dalam push kurang dari nilai minmum. Beri nama variabel ini y, jadi sekarang tumpukan kita akan terlihat seperti ini:

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

Saya telah mengganti namanya menjadi y1, y2, y3 untuk menghindari kebingungan bahwa semuanya akan memiliki nilai yang sama.

Point3:

Sekarang Mari kita coba mencari beberapa batasan di atas y1, y2 dan y3. Apakah Anda ingat kapan tepatnya kita perlu mengupdate minvalue saat melakukan pop (), hanya ketika kita telah memunculkan elemen yang sama dengan minvalue. Jika kita memunculkan sesuatu yang lebih besar dari nilai min, maka kita tidak perlu memperbarui nilai min. Jadi untuk memicu pembaruan nilai min, y1, y2 & y3 harus lebih kecil daripada nilai min yang sesuai. [Kami menghindari persamaan untuk menghindari duplikasi [Titik2]] sehingga batasannya adalah [y <nilai min].

Sekarang mari kembali ke mengisi y, kita perlu menghasilkan beberapa nilai dan meletakkan y pada saat mendorong, ingat. Mari kita ambil nilai yang akan datang untuk mendorong menjadi x yang kurang dari nilai prevMinvalue, dan nilai yang sebenarnya akan kita dorong dalam tumpukan menjadi y. Jadi satu hal yang jelas bahwa newMinValue = x, dan y <newMinvalue.

Sekarang kita perlu menghitung y (ingat y bisa berupa angka apa saja yang kurang dari newMinValue (x) jadi kita perlu mencari beberapa angka yang bisa memenuhi batasan kita) dengan bantuan prevMinvalue dan 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].

Jadi pada saat menekan x jika kurang dari prevMinvalue maka kami mendorong y [2 * x-prevMinValue] dan memperbarui newMinValue = x.

Dan pada saat pop jika stack berisi sesuatu yang kurang dari minValue maka itulah pemicu kami untuk memperbarui minVAlue. Kita harus menghitung prevMinValue dari curMinValue dan y. y = 2 * curMinValue - prevMinValue [Terbukti] prevMinVAlue = 2 * curMinvalue - y.

2 * curMinValue - y adalah angka yang perlu kita perbarui sekarang ke prevMinValue.

Kode untuk logika yang sama dibagikan di bawah ini dengan kompleksitas O (1) waktu dan O (1) ruang.

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

Ini adalah versi implementasi saya.

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

 void Push (nilai int)
 {
    // Membuat Anda menyusun dan mengisi nilainya
    MyStack S = new MyStack ();
    S-> elemen = nilai;

    jika (Stack.Empty ())
    {    
        // Karena tumpukan kosong, arahkan CurrentMiniAddress ke dirinya sendiri
        S-> CurrentMiniAddress = S;

    }
    lain
    {
         // Tumpukan tidak kosong

         // Ambil elemen teratas. Tanpa Pop ()
         MyStack * TopElement = Stack.Top ();

         // Ingat Selalu elemen TOP menunjuk ke
         // elemen minimum di seluruh tumpukan
         if (S-> elemen CurrentMiniAddress-> elemen)
         {
            // Jika nilai saat ini adalah minimum di seluruh tumpukan
            // lalu S menunjuk ke dirinya sendiri
            S-> CurrentMiniAddress = S;
         }
             lain
             {
                 // Jadi ini bukan jumlah minimum di seluruh tumpukan
                 // Jangan khawatir, TOP memegang elemen minimum
                 S-> CurrentMiniAddress = TopElement-> CurrentMiniAddress;
             }

    }
        Stack.Add (S);
 }

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

 int GetMinimum (Stack & stack)
 {
       if (! stack.Empty ())
       {
            MyStack * Atas = stack.top ();
            // Top selalu menunjuk ke minimumx
            kembali Top-> CurrentMiniAddress-> elemen;
        }
 }

Saya Setuju, ini membutuhkan elemen tambahan di struct Anda. Tapi ini menghilangkan menemukan minimum setiap kali kita memunculkan elemen.
Ganesh M

1
Jadi, setelah gagal memenuhi batasan pertanyaan, apakah Anda mendapatkan pekerjaan itu?
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

Saya menemukan solusi ini di sini

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

Ini Kode saya yang berjalan dengan O (1). Di sini saya menggunakan pasangan vektor yang berisi nilai yang didorong dan juga berisi nilai minimum hingga nilai yang didorong ini.


Ini adalah versi implementasi C ++ saya.

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

Apa yang ditambahkan ini, katakanlah, jawaban Jon Skeet ? Berapa banyak ruang yang digunakan ini untuk n menuju tak terhingga (lihat pertanyaan atau jawaban terkait)? Dengan bahasa pemrograman yang mengklaim mendukung OO, tampaknya lebih tepat untuk membuat tipe data (tidak terlalu abstrak) / (generik) Class- MinStack? Dokumentasi Java Oracle menyarankan untuk digunakan Deque.
greybeard

(Terima kasih telah mengambil petunjuk. (Komentar kode harus menjelaskan untuk apa, bagaimana, dan mengapa - menyebutkan bahwa suatu kondisi adalah suatu kondisi tidak membantu. Satu atau dua baris pertama sebaiknya tidak menjorok ke dalam, itu tercapai, saat ini, di mana , menyusut dan melebar …))
greybeard

0

Implementasi praktis untuk menemukan nilai minimum dalam Tumpukan Objek yang Dirancang Pengguna, bernama: Sekolah

Stack akan menyimpan Sekolah di Stack berdasarkan peringkat yang ditetapkan ke sekolah di wilayah tertentu, katakanlah, findMin () memberikan Sekolah tempat kami mendapatkan jumlah maksimum aplikasi untuk Penerimaan, yang pada gilirannya akan ditentukan oleh pembanding yang menggunakan peringkat yang terkait dengan sekolah di musim sebelumnya.

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

}

Juga Objek Sekolah adalah sebagai berikut:

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

}

Contoh ini mencakup hal-hal berikut: 1. Implementasi Stack untuk Objek yang Ditentukan Pengguna, di sini, Sekolah 2. Implementasi untuk metode hashcode () dan equals () menggunakan semua bidang Objek yang akan dibandingkan 3. Implementasi praktis untuk skenario di mana kita rqeuire untuk mendapatkan operasi Stack berisi agar berada di urutan O (1)


Tidak ada tag bahasa untuk pertanyaan ini (justru sebaliknya:): language-agnosticharap sebutkan apa yang Anda gunakan untuk kode tersebut (dan hapus yang kosong sebelumnya The Code for same is below:.) Bagaimana ini mendukung stack.pop()? (dan push()?)
greybeard

0

Berikut implementasi PHP yang dijelaskan dalam jawaban Jon Skeet sebagai implementasi kompleksitas ruang yang sedikit lebih baik untuk mendapatkan tumpukan maksimum dalam 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

Berikut adalah implementasi C ++ dari Jon Skeets Answer . Ini mungkin bukan cara yang paling optimal untuk mengimplementasikannya, tetapi melakukan persis seperti yang seharusnya.

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

Dan inilah pengemudi untuk kelasnya

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

Keluaran:

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

0

Kita dapat melakukan ini dalam kompleksitas ruang O (n) waktu dan O (1), seperti:

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

Saya pikir Anda cukup menggunakan LinkedList dalam implementasi stack Anda.

Pertama kali Anda memasukkan nilai, Anda meletakkan nilai ini sebagai kepala linkedlist.

maka setiap kali Anda push nilai, jika nilai baru <head.data, lakukan operasi prepand (yang berarti head menjadi nilai baru)

jika tidak, maka lakukan operasi penambahan.

Saat Anda membuat pop (), Anda memeriksa apakah min == linkedlist.head.data, jika ya, maka head = head.next;

Ini kode saya.

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

}

 }

Memiliki urutan angka. Dalam satu lingkaran, jika angkanya genap, letuskan dua item. Dorong nomornya dan cetak minimum.
greybeard

? Saya tidak mengerti komentar Anda
Zok

Kita dapat menyesuaikan metode pop () untuk memeriksa apakah nilai teratas == 0, jika demikian, kita menghapus daftar tertaut dengan membuat 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

Lihat solusi brilian di sini: https://www.geeksforgeeks.org/design-a-stack-that-supports-getmin-in-o1-time-and-o1-extra-space/

Di bawah ini adalah kode python yang saya tulis dengan mengikuti algoritme:

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

Untuk mendapatkan elemen dari Stack. Kita harus menggunakan Two stack .ie Stack s1 dan Stack s2.

  1. Awalnya, kedua tumpukan kosong, jadi tambahkan elemen ke kedua tumpukan

--------------------- Panggil Langkah 2 ke 4 secara rekursif -----------------------

  1. jika elemen baru ditambahkan ke tumpukan s1. Kemudian elemen pop dari tumpukan s2

  2. bandingkan elemen baru dengan s2. mana yang lebih kecil, dorong ke s2.

  3. pop dari stack s2 (yang berisi elemen min)

Kode terlihat seperti:

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

Saya pikir hanya operasi push yang menderita, sudah cukup. Implementasi saya mencakup setumpuk node. Setiap node berisi item data dan juga minimum pada saat itu. Minimum ini diperbarui setiap kali operasi dorong dilakukan.

Berikut beberapa poin untuk dipahami:

  • Saya mengimplementasikan tumpukan menggunakan Linked List.

  • Bagian atas penunjuk selalu mengarah ke item yang terakhir didorong. Ketika tidak ada item di atas tumpukan itu adalah NULL.

  • Ketika sebuah item didorong, sebuah simpul baru dialokasikan yang memiliki penunjuk berikutnya yang menunjuk ke tumpukan sebelumnya dan atas diperbarui untuk menunjuk ke simpul baru ini.

Satu-satunya perbedaan dengan implementasi tumpukan normal adalah bahwa selama push, pembaruan minimum anggota untuk node baru.

Silakan lihat kode yang diimplementasikan di C ++ untuk tujuan demonstrasi.

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

Dan keluaran dari program tersebut terlihat seperti ini:

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();
  }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.