getMinimum ()이 O (1)이되도록 스택을 설계합니다.


118

이것은 인터뷰 질문 중 하나입니다. getMinimum () 함수가 스택의 최소 요소를 반환하도록 정수 값을 보유하는 스택을 설계해야합니다.

예 : 아래 예를 고려하십시오.

사례 # 1

5-> 상단
1
4
6
2

getMinimum ()이 호출되면 최소 요소 인 1을 반환해야합니다. 
스택에. 

사례 # 2

stack.pop ()
stack.pop ()

참고 : 5와 1은 모두 스택에서 튀어 나옵니다. 그래서 그 후 스택
마치

4-> 상단
6
2

getMinimum ()이 호출되면 최소값 인 2를 반환해야합니다. 
스택.

공헌자 :

  1. getMinimum은 O (1)의 최소값을 반환해야합니다.
  2. 공간 제약도 설계시 고려해야하며 추가 공간을 사용하는 경우 일정한 공간이어야합니다.

답변:


180

편집 : 이것은 "상수 공간"제약 조건에 실패합니다. 기본적으로 필요한 공간을 두 배로 늘립니다. 어딘가에서 런타임 복잡성을 해치지 않고 (예 : 푸시 / 팝 O (n) 만들기) 그렇게 하지 않는 솔루션이 있다는 것은 매우 의심 스럽습니다 . 이것은 필요한 공간 의 복잡성 을 변경하지 않습니다 . 예를 들어 O (n) 공간 요구 사항이있는 스택이있는 경우, 이것은 다른 상수 계수를 가진 O (n)입니다.

상수 공간이 아닌 솔루션

"스택에서 낮은 모든 값의 최소값"의 "중복"스택을 유지하십시오. 메인 스택을 팝할 때 최소 스택도 팝하십시오. 메인 스택을 푸시 할 때 새 요소 또는 현재 최소값 중 더 낮은 값을 푸시합니다. getMinimum()그런 다음 minStack.peek().

따라서 귀하의 예를 사용하면 다음과 같습니다.

Real stack        Min stack

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

두 번 터지면 다음을 얻습니다.

Real stack        Min stack

4                 2
6                 2
2                 2

정보가 충분하지 않은 경우 알려주세요. 당신이 그것을 할 때 간단하지만 처음에는 약간의 머리를 긁을 수 있습니다. :)

(물론 단점은 공간 요구 사항을 두 배로 늘린다는 것입니다. 그러나 실행 시간은 크게 영향을받지 않습니다. 즉, 여전히 동일한 복잡성입니다.)

편집 : 약간 더 이상하지만 일반적으로 더 나은 공간이있는 변형이 있습니다. 우리는 여전히 min 스택을 가지고 있지만, 우리는 메인 스택에서 가져온 값이 min 스택의 값과 같을 때만 팝합니다. 우리는 푸시 메인 스택 미만이다 상 값이 밀려 최소 스택 같거나 현재의 최소값에 관한 것이다. 이렇게하면 최소값이 중복됩니다. 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                 

이것은 동일한 최악의 경우 공간 복잡성 (원래 스택의 두 배)으로 끝나지만 "새로운 최소값 또는 같음"을 거의 얻지 못하면 훨씬 더 나은 공간 사용으로 끝납니다.

편집 : 여기 Pete의 사악한 계획의 구현이 있습니다. 철저히 테스트하지는 않았지만 괜찮은 것 같아요 :)

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 : 런타임이 문제가되는 이유는 무엇입니까? 단일 스택의 두 배 밖에 걸리지 않습니다. 즉, push () 및 pop ()뿐만 아니라 getMinimum ()의 경우에도 여전히 O (1) 시간입니다 . 뛰어난 성능입니다!
j_random_hacker

4
단일 변수가있는 경우 예제에서 "1"을 표시하면 어떻게됩니까? 이전 최소값이 "2"라는 것을 알아 내야합니다. 모든 것을 스캔하지 않고서는 불가능합니다.
Jon Skeet

1
@Ganesh : 그러면 pop () 할 때마다 O (n) 검색을 사용하여 새로운 최소값을 찾을 필요가 없습니까?
j_random_hacker

2
다른 의견을 읽으면서 "스택 디자인 자체에서"라고 말할 때 "각 요소에서"를 의미합니까? 그렇다면 요소 유형의 크기에 따라 잠재적으로 메모리 요구 사항을 거의 두 배로 늘릴 수 있습니다. 개념적으로 두 개의 스택과 동일합니다.
Jon Skeet

1
@Ganesh : 불행히도 추가 스택이 없다는 것은 위에 포함 된 공간 절약 최적화를 수행 할 수 없음을 의미합니다. "최소 및 요소"를 함께 유지하는 것은 언어에 따라 다르지만 같은 크기 (더 적은 오버 헤드-배열, 목록 노드 등)의 두 스택보다 더 효율적일 것입니다.
Jon Skeet

41

최소값을 유지할 필드를 추가하고 Pop () 및 Push () 중에 업데이트합니다. 이렇게하면 getMinimum ()은 O (1)이되지만 Pop ()과 Push ()는 조금 더 많은 작업을 수행해야합니다.

최소값이 팝되면 Pop ()은 O (n)이되고 그렇지 않으면 둘 다 O (1)이됩니다. 크기를 조정할 때 Push ()는 Stack 구현에 따라 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 ()는 문제가되지 않습니다.
Georg Schölly

4
@sigjuice : 맞습니다. 나는 :) 덜 극적인 뭔가에 "고통"이라는 단어가 변경됩니다 생각
브라이언 라스무센

2
@Ganesh M "요소 추가 필드"N 요소에 추가 필드가있는 경우 상수 공간이 아니라 O (N) 추가입니다.
Pete Kirkham

1
작업 중에 최소값이 스택에서 튀어 나오면 다음 최소값은 어떻게 찾습니까? 이 방법은 시나리오 ... 지원하지 않습니다
Sharat 찬드라

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

}

현재 최소값을 명시 적으로 저장하고 최소값이 변경되면 값을 푸시하는 대신 새 최소값의 다른쪽에 동일한 차이를 푸시합니다 (최소 = 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 ++ 버전 입니다. 건배.
Tony Delroy 2014-07-30

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

음, 런타임 제약 무엇 pushpop? 상수 일 필요가없는 경우 두 작업에서 최소값을 계산하면됩니다 ( O ( n )). 그렇지 않으면 일정한 추가 공간으로 어떻게 할 수 있는지 알 수 없습니다.


4
+1, hehe ... 오래된 "규칙을 구부리기"트릭 ... 비슷한 방식으로 O (1) 시간에 모든 크기 배열을 정렬하는 정렬 알고리즘을 알고 있지만 결과를 초래 O (nlog N) ... : 오버
j_random_hacker

3
Haskell에서는 모든 것이 일정한 시간입니다! (결과를 인쇄하려는 경우 제외)
Henk

1
불량 문제 사양에 대해 +1합니다. 나도 않았다, 그러나 피트 Kirkham의 솔루션은 .... 아주 우아하게 그것을 않습니다 - "나는이 작업을 수행 할 수있는 방법을 볼 수 없습니다"
토니 델로이

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

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

시도 해봐. 나는 그것이 질문에 대한 답이라고 생각합니다. 모든 쌍의 두 번째 요소는 해당 요소가 삽입되었을 때 표시되는 최소값을 제공합니다.


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> min 측면에서 추가 공간을 사용합니다.
Arpit

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]는 하나의 변수에 저장되는 설명 목적으로 만 작성됩니다.

실제 문제는 최소값 인 값이 그 시점에서 제거 될 때 스택을 반복하지 않고 다음 최소 요소가 무엇인지 어떻게 알 수 있다는 것입니다.

예를 들어 6이 터졌을 때 스택에서와 같이 최소 요소가 2이기 때문에 최소 요소가 아니므로 최소 값을 업데이트하지 않고도 안전하게 제거 할 수 있습니다.

그러나 2를 뽑으면 최소값이 지금 2 인 것을 볼 수 있으며 이것이 튀어 나오면 최소값을 3으로 업데이트해야합니다.

Point1 :

이제주의 깊게 관찰하면이 특정 상태 [2, minvalue = 2]에서 minvalue = 3을 생성해야합니다. 또는 스택에서 depper로 이동하면이 특정 상태 [3, minvalue = 3]에서 minvalue = 7을 생성해야합니다. 또는 스택에서 더 depper로 이동하면이 특정 상태에서 minvalue = 8을 생성해야합니다 [7, minvalue = 7]

위의 3 가지 경우 모두에서 우리가 생성해야하는 값은 둘 다 동일한 두 변수에 따라 달라지는 공통점을 발견 했습니까? 옳은. 현재 최소값보다 작은 요소를 푸시 할 때 기본적으로 해당 요소를 스택에 푸시하고 최소값에서도 동일한 숫자를 업데이트하기 때문에 이런 일이 발생하는 이유입니다.

Point2 :

그래서 우리는 기본적으로 동일한 숫자의 중복을 스택에 한 번, minvalue 변수에 한 번 저장합니다. 위의 CASES에서 볼 수 있듯이이 중복을 피하고 유용한 데이터를 스택 또는 minvalue에 저장하여 이전 최소값을 생성하는 데 집중해야합니다.

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로 이름을 바꿨습니다.

Point3 :

이제 y1, y2 및 y3에 대한 제약 조건을 찾아 보겠습니다. minvalue와 동일한 요소를 팝했을 때만 pop ()을 수행하는 동안 minvalue를 정확히 업데이트해야 할 때를 기억하십니까? minvalue보다 큰 것을 팝하면 minvalue를 업데이트 할 필요가 없습니다. 따라서 minvalue의 업데이트를 트리거하려면 y1, y2 & y3이 해당하는 minvalue보다 작아야합니다. [우리는 중복을 피하기 위해 평등을 거부합니다 [Point2]] 그래서 제약은 [y <minValue]입니다.

이제 y를 채우기 위해 돌아와 보겠습니다. 값을 생성하고 푸시 할 때 y를 입력해야합니다. 기억하세요. push를 위해 오는 값을 prevMinvalue보다 작은 x로 취하고 실제로 스택에 푸시 할 값을 y로합시다. 따라서 한 가지는 newMinValue = x 및 y <newMinvalue라는 것이 분명합니다.

이제 우리는 prevMinvalue와 x (newMinvalue)의 도움으로 y를 계산해야합니다 (y는 newMinValue (x)보다 작은 숫자 일 수 있으므로 제약 조건을 충족 할 수있는 숫자를 찾아야합니다).

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

 무효 Push (int 값)
 {
    // 구조를 만들고 값을 채 웁니다.
    MyStack S = new MyStack ();
    S-> 요소 = 값;

    if (Stack.Empty ())
    {    
        // 스택이 비어 있으므로 CurrentMiniAddress를 자신을 가리 킵니다.
        S-> CurrentMiniAddress = S;

    }
    그밖에
    {
         // 스택이 비어 있지 않습니다.

         // 최상위 요소를 검색합니다. Pop () 없음
         MyStack * TopElement = Stack.Top ();

         // 항상 TOP 요소가
         // 전체 스택의 최소 요소
         if (S-> 요소 CurrentMiniAddress-> 요소)
         {
            // 현재 값이 전체 스택에서 최소값 인 경우
            // 그러면 S가 자신을 가리 킵니다.
            S-> CurrentMiniAddress = S;
         }
             그밖에
             {
                 // 따라서 이것은 전체 스택의 최소값이 아닙니다.
                 // 걱정하지 마세요. TOP은 최소 요소를 유지합니다.
                 S-> CurrentMiniAddress = TopElement-> CurrentMiniAddress;
             }

    }
        Stack.Add (S);
 }

 무효 Pop ()
 {
     if (! Stack.Empty ())
     {
        Stack.Pop ();
     }  
 }

 int GetMinimum (스택 및 스택)
 {
       if (! stack.Empty ())
       {
            MyStack * Top = stack.top ();
            // Top은 항상 최소값을 가리 킵니다.
            return Top-> CurrentMiniAddress-> element;
        }
 }

동의합니다. 구조체에 추가 요소가 필요합니다. 그러나 이것은 요소를 팝할 때마다 최소값을 찾는 것을 제거합니다.
Ganesh M

1
그래서, 질문의 제약을 충족하지 못해서 일자리를 얻었습니까?
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

여기 에서이 솔루션을 찾았 습니다.

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

이것은 Jon Skeet의 대답에 무엇을 추가 합니까? 무한대를 향한 n에 대해 얼마나 많은 공간을 사용합니까 (질문 또는 링크 된 답변 참조)? OO를 지원한다고 주장하는 프로그래밍 언어의 경우 (추상적이지 않은) 데이터 유형 / (일반) Class- MinStack? Oracle의 Java 설명서Deque.
greybeard

(힌트를 받아 주셔서 감사합니다. (코드 주석은 조건이 조건이라는 것을 언급하는 것이 도움이되지 않는 목적, 방법 및 이유를 설명해야합니다. 처음 한두 줄은 들여 쓰지 않는 것이 좋습니다. 달성 됨, 현재, 여기서 , 축소확대 )) ...
수염이 희끗 희끗 한

0

사용자 디자인 개체 스택에서 최소값을 찾기위한 실용적인 구현 : School

스택은 특정 지역의 학교에 할당 된 순위에 따라 스택에 학교를 저장할 것입니다. 예를 들어 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"));
    }

}

또한 School Object는 다음과 같습니다.

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. 사용자 정의 객체에 대한 스택 구현, 여기서는 School 2. 비교할 객체의 모든 필드를 사용하는 hashcode () 및 equals () 메서드 구현 3. 시나리오에 대한 실제 구현 스택을 가져 오는 rqeuire에는 O (1) 순서대로 작업이 포함됩니다.


이 질문에 대한 언어 태그가 없습니다 (반대로 :) : language-agnostic코드에 사용할 내용을 지정하고 앞에 공백을 제거하십시오 The Code for same is below:. 어떻게 지원 stack.pop()합니까? (와 push()?)
수염이 희끗 희끗 한

0

다음 은 O (1)에서 스택의 최대 값을 얻기 위해 약간 더 나은 공간 복잡성 구현으로 Jon Skeet의 답변에 설명 된 PHP 구현입니다 .

<?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이면 사전 작업을 수행합니다 (즉, 헤드가 새 값이 됨).

그렇지 않은 경우 추가 작업을 수행하십시오.

pop ()을 만들 때 min == linkedlist.head.data인지 확인하고, 그렇다면 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();

}

 }

일련의 숫자가 있습니다. 루프에서 숫자가 짝수이면 두 항목을 팝합니다. 숫자를 누르고 최소값을 인쇄하십시오.
greybeard

? 나는 당신의 의견을 이해하지 않습니다
Zok

pop () 메서드를 조정하여 최상위 값 == 0인지 확인할 수 있습니다. 그렇다면 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

여기에서 훌륭한 솔루션을 보았습니다 : https://www.geeksforgeeks.org/design-a-stack-that-supports-getmin-in-o1-time-and-o1-extra-space/

Bellow는 알고리즘에 따라 작성한 파이썬 코드입니다.

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

스택에서 요소를 가져옵니다. Two stack .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

푸쉬 조작만으로도 충분하다고 생각합니다. 내 구현에는 노드 스택이 포함됩니다. 각 노드에는 데이터 항목과 해당 순간의 최소값이 포함됩니다. 이 최소값은 푸시 작업이 완료 될 때마다 업데이트됩니다.

다음은 이해해야 할 몇 가지 사항입니다.

  • Linked List를 사용하여 스택을 구현했습니다.

  • 포인터 상단은 항상 마지막으로 푸시 된 항목을 가리 킵니다. 해당 스택에 항목이없는 경우 최상위는 NULL입니다.

  • 항목이 푸시되면 이전 스택을 가리키는 다음 포인터가있는 새 노드가 할당되고이 새 노드를 가리 키도록 상단이 업데이트됩니다.

일반적인 스택 구현과의 유일한 차이점은 푸시하는 동안 새 노드에 대한 구성원 min을 업데이트한다는 것입니다.

데모 목적으로 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.