getMinimum()がO(1)になるようにスタックを設計する


118

これはインタビューの質問の1つです。getMinimum()関数がスタック内の最小要素を返すように、整数値を保持するスタックを設計する必要があります。

例:以下の例を検討してください

ケース#1

5->トップ
1
4
6
2

getMinimum()が呼び出されると、最小要素である1を返す必要があります 
スタック。 

ケース#2

stack.pop()
stack.pop()

注:5と1の両方がスタックからポップされます。この後、スタック
のように見えます

4->トップ
6
2

getMinimum()が呼び出されたときは、2を返す必要があります。これは、 
スタック。

Constriants:

  1. getMinimumはO(1)の最小値を返す必要があります
  2. スペースの制約も設計時に考慮する必要があり、余分なスペースを使用する場合は一定のスペースにする必要があります。

回答:


180

編集:これは「一定のスペース」制約に失敗します-基本的に必要なスペースが2倍になります。実行時の複雑さをどこかに壊さずに(たとえば、プッシュ/ポップO(n)を作成せずに)、それを行わない解決策があることを私は非常に疑っています。これは、必要なスペースの複雑さを変更しないことに注意してください。たとえば、O(n)スペース要件のスタックがある場合、これは、異なる定数係数を使用した場合でも、O(n)になります。

非定数空間ソリューション

「スタック内のすべての値の最小値」の「重複」スタックを保持します。メインスタックをポップするときは、最小スタックもポップします。メインスタックをプッシュするときは、新しい要素または現在の最小値のいずれか低い方をプッシュします。getMinimum()その後、次のように実装されますminStack.peek()

したがって、例を使用すると、次のようになります。

Real stack        Min stack

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

2回ポップすると、次のようになります。

Real stack        Min stack

4                 2
6                 2
2                 2

これでは不十分な場合はお知らせください。それを手に取ると簡単ですが、最初は少し頭を悩ますかもしれません:)

(もちろん、欠点は、スペース要件が2倍になることです。ただし、実行時間に大きな影響はありません。つまり、複雑さは同じです。)

編集:少し手間のかかるバリエーションがありますが、一般により良いスペースがあります。まだ最小スタックがありますが、メインスタックからポップする値が最小スタックの値と等しい場合にのみ、そこからポップします。我々は、プッシュメインスタックにプッシュされる値未満のとき分スタックにまたはそれに等しい電流最小値に。これにより、最小値の重複が可能になります。getMinimum()まだピーク操作です。たとえば、元のバージョンを取得してもう一度1を押すと、次のようになります。

Real stack        Min stack

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

上記からポップすると、1 == 1なので、両方のスタックからポップします。

Real stack        Min stack

5  --> TOP        1
1                 2
4                 
6                 
2                 

5> 1であるため、再びポップすると、メインスタックからのポップされます。

Real stack        Min stack

1                 1
4                 2
6                 
2                 

1 == 1であるため、再度ポップすると両方のスタックがポップされます。

Real stack        Min stack

4                 2
6                 
2                 

これは、ワーストケースと同じ最悪の場合のスペースの複雑さ(元のスタックの2倍)になりますが、「新しい最小値または等しい値」をめったに取得しない場合は、はるかに優れたスペース使用になります。

編集:これはピートの邪悪な計画の実装です。私はそれを完全にテストしていませんが、それは大丈夫だと思います :)

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
賢い!@Ganesh:ランタイムに問題があるのはなぜですか?これは、単一のスタックの2倍の時間しかかかりません。つまり、push()とpop()のほか、getMinimum()の場合もO(1)時間です。これは優れたパフォーマンスです。
j_random_hacker

4
単一の変数がある場合、例の「1」をポップするとどうなりますか?以前の最小値は「2」であったことを理解する必要があります。これは、すべてをスキャンしないと不可能です。
ジョンスキート

1
@Ganesh:次に、pop()を実行するたびにO(n)検索を使用して新しい最小値を見つける必要がありますか?
j_random_hacker 2009年

2
他のコメントを読んでいるだけで、「スタックデザイン自体」とは、「各要素内」という意味ですか?その場合でも、要素タイプのサイズによっては、メモリ要件がほぼ2倍になる可能性があります。概念的には2つのスタックと同じです。
Jon Skeet、

1
@Ganesh:残念ながら、追加のスタックがないということは、上記に含めた省スペースの最適化を行うことができないことを意味します。「最小要素」を維持することは、言語に依存しますが、同じサイズの2つのスタック(オーバーヘッド、配列、リストノードなど)よりもおそらく効率的です。
Jon Skeet、

41

最小値を保持するフィールドを追加し、Pop()およびPush()の実行中に更新します。そうすればgetMinimum()はO(1)になりますが、Pop()とPush()はもう少し作業を行う必要があります。

最小値がポップされた場合、Pop()はO(n)になります。それ以外の場合は、両方ともO(1)のままです。Stackの実装により、Push()のサイズを変更するとO(n)になります。

ここに簡単な実装があります

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

申し訳ありませんが、なぜpop()とpush()が影響を受けるのか理解できませんでしたか?
Ganesh M

11
pop()では、O(n)をとる「新しい」最小要素を見つける必要があります。この操作はまだO(1)なので、Push()は影響を受けません。
GeorgSchölly2009年

4
@sigjuice:正解です。私は「苦しみ」という言葉をそれほど劇的ではないものに変更すると思います:)
ブライアン・ラスムッセン

2
@Ganesh M「要素追加フィールド」N要素に追加フィールドがある場合、それは定数スペースではなく、O(N)追加です。
ピートカーカム

1
操作中にスタックから最小値がポップされた場合、次の最小値はどのようにして見つけられますか?この方法はそのシナリオをサポートしていません...
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();
    }

}

現在の最小値を明示的に保存し、最小値が変化した場合、値をプッシュする代わりに、新しい最小値の反対側と同じ差の値をプッシュします(min = 7で5を押すと、代わりに3をプッシュします(5- | 7-5 | = 3)およびminを5に設定します。minが5のときに3をポップすると、ポップされた値がminより小さいことがわかります。そのため、手順を逆にして、新しいminの7を取得し、前の値を返します。分)。現在の最小値を変更しない値は現在の最小値よりも大きいため、最小値を変更する値と変更しない値を区別するために使用できるものがあります。

固定サイズの整数を使用する言語では、値の表現から少しスペースを借りているため、アンダーフローが発生してアサートが失敗します。しかし、それ以外の場合、それは一定の余分なスペースであり、すべての操作は依然としてO(1)です。

代わりにリンクリストに基づくスタックには、Cで次のポインターの最下位ビット、またはJavaでリンクリストのオブジェクトのタイプなどから借用できる他の場所があります。Javaの場合、リンクごとにオブジェクトのオーバーヘッドがあるため、隣接するスタックと比較して使用されるスペースが多くなります。

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では、オーバーヘッドはなく、次のポインターのlsbを借りることができます。

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

ただし、これらはいずれも真のO(1)ではありません。これらは、これらの言語の数値、オブジェクト、またはポインタの表現の穴を利用するため、実際にはこれ以上のスペースは必要ありません。しかし、よりコンパクトな表現を使用した理論上のマシンでは、それぞれの表現にその表現に追加のビットを追加する必要があります。


+1非常にエレガントです... ideoneで実行されているC ++バージョンをここに移植しました。乾杯。
トニーデルロイ、2014

Javaではpop()、最後にプッシュされた値Integer.MIN_VALUE(たとえば、push 1、push Integer.MIN_VALUE、pop)の場合、これは誤った結果を生成します。これは、上記のアンダーフローが原因です。それ以外の場合は、すべての整数値に対して機能します。
Theo

13

言及されたすべての制約を満たすソリューションを見つけました(一定時間の操作) 一定の余分なスペース

アイデアは、最小値と入力数の差を格納し、最小値が最小でなくなった場合に最小値を更新することです。

コードは次のとおりです。

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

クレジットは次の場所に移動します:https : //leetcode.com/discuss/15679/share-my-java-solution-with-only-one-stack


これは機能します。スタック内の負の数でも試してみました。そして、覚えるのに十分なほど単純です。ありがとう。
r9891

7

まあ、のランタイム制約何pushとはpop?それらが定数である必要がない場合は、これらの2つの演算(On)にする)の最小値を計算するだけです。それ以外の場合、一定の追加スペースを使用してこれを行う方法はわかりません。


4
+1、hehe ...古い "ベンドルール"トリック...同様に、O(1)時間で任意のサイズの配列をソートするソートアルゴリズムを知っていますが、結果としてO(nlog n)オーバーヘッドが発生します... :)
j_random_hacker 2009年

3
Haskellでは、すべてが一定の時間です!(結果を印刷する場合を除く)
Henk

1
貧弱な問題の仕様を示すための+1。「これがどのように行われるかわかりません」-私もそうではありませんでしたが、ピートカーカムのソリューションは非常にエレガントにそれを行います...
トニー・デルロイ14

1

O(1)で実行する私のコードは次のとおりです。私が投稿した以前のコードでは、最小要素がポップされると問題が発生しました。コードを変更しました。これは、現在のプッシュされた要素の上のスタックに存在する最小要素を維持する別のスタックを使用します。

 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
ここでコードの記述に使用されているプログラミング言語を教えてください。潜在的な訪問者が構文に基づいて何が起こっているかを知る手助けをします。私はそれをC#と想定していますが、誰かがそうしない場合はどうなりますか?
realPK 2014

1

別の種類のスタックを使用しました。これが実装です。

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

出力:

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

それを試してみてください。私はそれが質問に答えると思います。各ペアの2番目の要素は、その要素が挿入されたときに見られる最小値を示します。


1

ここに完全なコードを投稿して、特定のスタックで最小値と最大値を見つけます。

時間の複雑さは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());
    }
}

問題が発生した場合はお知らせください

ありがとう、Vikash


1

元のスタッククラスを拡張して、最小トラッキングを追加するだけです。元の親クラスが他のすべてを通常どおり処理するようにします。

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

このソリューションは、Stack <Integer>の観点からも余分なスペースを使用しています。
アーピット

1

これは、高評価リストを使用したJavaでの私の解決策です。

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

作業するスタックはこれだとしましょう:

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

上記の表現では、スタックは左の値によってのみ構築されます。右の値の[minvalue]は、1つの変数に格納される例示の目的でのみ書き込まれます。

実際の問題は、最小値である値がその時点で削除されたときに、スタックを反復処理せずに次の最小要素をどのようにして知ることができるかです。

たとえば、スタックで6 getがポップされたときのように、最小要素は2であるため、これは最小要素ではありません。したがって、min値を更新せずにこれを安全に削除できます。

しかし、2をポップすると、最小値は現在2であることがわかります。これがポップアウトされた場合、最小値を3に更新する必要があります。

ポイント1:

ここで注意深く観察すると、この特定の状態からminvalue = 3を生成する必要があります[2、minvalue = 2]。または、スタックでdepperを実行する場合、この特定の状態からminvalue = 7を生成する必要があります[3、minvalue = 3]またはスタックでさらにdepperを実行する場合、この特定の状態からminvalue = 8を生成する必要があります[7、minvalue = 7]

上記の3つのケースすべてに共通する点に気づきましたか?生成する必要がある値は、両方が等しい2つの変数に依存しています。正しい。現在のminvalueよりも小さい要素をプッシュすると、基本的にその要素がスタックにプッシュされ、minvalueの同じ数も更新されるため、これが発生するのはなぜですか。

ポイント2:

したがって、基本的には、スタックに1回、minvalue変数に1回、同じ数の複製を格納します。上記のCASESに示すように、この重複の回避に焦点を当て、スタックまたは最小値に有用なデータを保存して、以前の最小値を生成する必要があります。

pushに格納する値がminmumvalueより小さい場合に、スタックに何を格納するかに焦点を当てましょう。この変数にyという名前を付けます。これで、スタックは次のようになります。

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

すべての値が同じになるという混乱を避けるために、名前をy1、y2、y3に変更しました。

ポイント3:

次に、y1、y2、およびy3に対するいくつかの制約を見つけてみましょう。pop()の実行中に正確にminvalueを更新する必要があるのはいつか、覚えていますか。minvalueに等しい要素をポップしたときだけです。minvalueより大きい値をポップする場合、minvalueを更新する必要はありません。したがって、minvalueの更新をトリガーするには、対応するminvalueよりもy1、y2&y3を小さくする必要があります。[重複を避けるために等式を使用します[Point2]]制約は[y <minValue]です。

さて、yを入力するために戻ってみましょう。値を生成し、プッシュ時にyを置く必要があることを思い出してください。pushのために来ている値を、prevMinvalueよりも小さいxとし、スタックに実際にpushする値をyとします。したがって、newMinValue = xかつy <newMinvalueであることは明らかです。

ここで、yを計算する必要があります(yはnewMinValue(x)よりも小さい任意の数にすることができるので、prevMinvalueおよび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].

したがって、xをプッシュするときに、それがprevMinvalueより小さい場合は、y [2 * x-prevMinValue]をプッシュし、newMinValue = xを更新します。

ポップ時にスタックにminValueより小さい値が含まれている場合、それがminVAlueを更新するトリガーになります。curMinValueとyからprevMinValueを計算する必要があります。y = 2 * curMinValue-prevMinValue [証明済み] prevMinVAlue = 2 * curMinvalue-y。

2 * curMinValue-yは、prevMinValueに更新する必要がある数値です。

同じロジックのコードは、O(1)時間とO(1)空間の複雑さで以下に共有されます。

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

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

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

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

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

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

        cout << "Top Most Element is: "; 

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

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

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

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

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

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

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

        else
           s.push(x); 

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

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

    return 0; 
} 

0

これが私の実装バージョンです。

 struct MyStack {
    int要素。
    int * CurrentMiniAddress;
 };

 void Push(int value)
 {
    //構造を作成し、値を入力します
    MyStack S = new MyStack();
    S-> element = value;

    if(Stack.Empty())
    {    
        //スタックが空なので、CurrentMiniAddressをそれ自体にポイントします
        S-> CurrentMiniAddress = S;

    }
    そうしないと
    {
         //スタックは空ではありません

         //一番上の要素を取得します。ポップなし
         MyStack * TopElement = Stack.Top();

         //常にTOP要素が
         //スタック全体の最小要素
         if(S->要素CurrentMiniAddress->要素)
         {
            //現在の値がスタック全体の最小値である場合
            //次にSはそれ自体を指します
            S-> CurrentMiniAddress = S;
         }
             そうしないと
             {
                 //したがって、これはスタック全体の最小値ではありません
                 //心配はいりません。TOPは最小要素を保持しています
                 S-> CurrentMiniAddress = TopElement-> CurrentMiniAddress;
             }

    }
        Stack.Add(S);
 }

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

 int GetMinimum(スタックとスタック)
 {
       if(!stack.Empty())
       {
            MyStack * Top = stack.top();
            //上は常に最小値を指します
            Top-> CurrentMiniAddress-> elementを返します。
        }
 }

同意します。これには、構造体に追加の要素が必要です。しかし、これにより、要素をポップするたびに最小値を見つけることがなくなります。
Ganesh M

1
それで、質問の制約を満たさなかったので、あなたは仕事を得ましたか?
ピートカーカム

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

ここでこの解決策を見つけまし

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

O(1)で実行する私のコードは次のとおりです。ここでは、プッシュした値とこのプッシュした値までの最小値を含むベクトルのペアを使用しました。


これがC ++実装の私のバージョンです。

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

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

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

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

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

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

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



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

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

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

        }

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

        public static void main(String args[]) {

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

            DeleteMinFromStack deleteMinFromStack = new DeleteMinFromStack();

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

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

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

これは、例えばジョン・スキートの答えに何を追加しますか?これは、無限大に向かってnにどのくらいのスペースを使用しますか(質問またはリンクされた回答を参照してください)?オブジェクト指向をサポートすると主張するプログラミング言語では、(それほど抽象的ではない)データ型/(汎用)を作成する方が適切と思われますClass- MinStackOracleのJavaドキュメントでは、の使用を推奨していますDeque
greybeard 2016

(ヒントを取ってくれてありがとう(コードのコメントは何-ため、どのように、そしてなぜを説明しなければならない- 。条件が条件であることを言及することは有益ではありません最初の1行か2行は、より良い、それがされ、インデントされていない。現在、達成し、前記、縮小して拡大 …))
greybeard '28 / 09/28

0

ユーザーがデザインしたオブジェクトのスタックで最小値を見つけるための実用的な実装。

スタックは、特定の地域の学校に割り当てられたランクに基づいて、学校をスタックに格納します。たとえば、findMin()は、入学申請の最大数を取得する学校を提供します。前シーズンの学校に関連するランクを使用するコンパレータ。

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

}

また、学校オブジェクトは次のとおりです。

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

}

この例では、以下について説明します。1.ユーザー定義オブジェクトのスタックの実装、ここでは学校2.比較するオブジェクトのすべてのフィールドを使用するhashcode()およびequals()メソッドの実装3.シナリオの実際的な実装スタックを取得するためのrqeuireには、O(1)の順になる操作が含まれています


この質問に言語タグはありません(まったく反対:):language-agnosticコードに使用するものを指定してください(そして、前に空白を削除してThe Code for same is below:ください)。これはどのようにサポートされstack.pop()ますか?(およびpush()?)
greybeard 2016年

0

以下は、Jon Skeetの回答で説明されているPHP実装で、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

以下は、Jon Skeets AnswerのC ++実装です。それはそれを実装する最適な方法ではないかもしれませんが、それはそれが想定していることを正確に行います。

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

そして、これがクラスのドライバーです

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

出力:

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

0

次のように、O(n)時間とO(1)空間の複雑さでこれを行うことができます。

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

スタック実装でLinkedListを単純に使用できると思います。

初めて値をプッシュするとき、この値をリンクリストの先頭として配置します。

その後、値をプッシュするたびに、新しい値<head.dataの場合、prepand操作を実行します(つまり、ヘッドが新しい値になります)

そうでない場合は、追加操作を行います。

pop()を作成するときに、min == linkedlist.head.dataかどうかを確認し、yesの場合は、head = head.next;を確認します。

これが私のコードです。

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

}

 }

一連の数字を持っている。ループで、数値が偶数の場合は、2つのアイテムをポップします。数字を押して最小値を印刷します。
greybeard 2017

?私はあなたのコメントを理解していません
Zok

私たちは、そうであれば、トップ値== 0かどうかを確認するポップ()メソッドを調整することができ、私たちが行うことで、リンクされたリストを消去min.head = nullを、min.head.next =ヌル
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

ここで素晴らしいソリューションを見ました:https : //www.geeksforgeeks.org/design-a-stack-that-supports-getmin-in-o1-time-and-o1-extra-space/

以下は、私がアルゴリズムに従って記述したpythonコードです。

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から最小要素を取得します。2つのスタック.ie Stack s1とStack s2を使用する必要があります。

  1. 最初は両方のスタックが空なので、両方のスタックに要素を追加します

---------------------再帰的にステップ2から4 -----------------------を呼び出します

  1. スタックs1に新しい要素が追加された場合。スタックs2から要素をポップします。

  2. 新しい要素をs2と比較します。どちらが小さいか、s2にプッシュします。

  3. スタックs2からポップ(最小要素を含む)

コードは次のようになります。

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

プッシュ操作だけで十分だと思います。私の実装にはノードのスタックが含まれています。各ノードには、データ項目とその瞬間の最小値が含まれています。この最小値は、プッシュ操作が行われるたびに更新されます。

理解のためのいくつかのポイントはここにあります:

  • リンクリストを使用してスタックを実装しました。

  • ポインターの上部は常に最後にプッシュされたアイテムを指します。そのスタックにアイテムがない場合、トップはNULLです。

  • アイテムがプッシュされると、前のスタックを指す次のポインターを持つ新しいノードが割り当てられ、topはこの新しいノードを指すように更新されます。

通常のスタック実装との唯一の違いは、プッシュ中に新しいノードのメンバー最小値を更新することです。

デモ目的でC ++に実装されているコードをご覧ください。

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

そして、プログラムの出力は次のようになります。

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();
  }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.