Как найти максимальное число в стеке

Improve Article

Save Article

Like Article

  • Read
  • Discuss
  • Improve Article

    Save Article

    Like Article

    Given a stack of integers. The task is to design a special stack such that the maximum element can be found in O(1) time and O(1) extra space.

    Examples

    Given Stack :
    2
    5
    1
    64   --> Maximum
    
    So Output must be 64 when getMax() is called.

    Below are the different functions designed to push and pop elements from the stack. 

    Push(x) : Inserts x at the top of stack. 

    • If stack is empty, insert x into the stack and make maxEle equal to x.
    • If stack is not empty, compare x with maxEle. Two cases arise:
      • If x is less than or equal to maxEle, simply insert x.
      • If x is greater than maxEle, insert (2*x – maxEle) into the stack and make maxEle equal to x. For example, let previous maxEle was 3. Now we want to insert 4. We update maxEle as 4 and insert 2*4 – 3 = 5 into the stack.

    Pop() : Removes an element from top of stack. 

    • Remove element from top. Let the removed element be y. Two cases arise:
      • If y is less than or equal to maxEle, the maximum element in the stack is still maxEle.
      • If y is greater than maxEle, the maximum element now becomes (2*maxEle – y), so update (maxEle = 2*maxEle – y). This is where we retrieve previous maximum from current maximum and its value in stack. For example, let the element to be removed be 5 and maxEle be 4. We remove 5 and update maxEle as 2*4 – 5 = 3.]

    How does the Above Equation work?  

    While pushing x into stack if x is greater than maxEle we push modified value = 2 * x-maxEle.  
    So, x > val 
    => x-val>0 
    => adding x to both sides 2x – val >x (this is our updated maxEle  from next steps). 
    Means the modified value is greater than maxEle.
    After popped out the maxEle should be updated 
    so maxEle = 2*maxEle – y (top value) 
    = 2*maxEle – (2*x- previousMax) 
    = 2*maxEle – 2*maxEle (maxELe = x in next steps) + previousMax   
    = previousMax.

     Important Points: 

    • Stack doesn’t hold actual value of an element if it is maximum so far.
    • Actual maximum element is always stored in maxEle

    Illustration:

    Push(x):

    • Number to be Inserted: 3, Stack is empty, so insert 3 into stack, and maxEle = 3.
    • Number to be Inserted: 5, Stack is not empty, 5> maxEle, insert (2*5-3) into stack and maxEle = 5.
    • Number to be Inserted: 2, Stack is not empty, 2< maxEle, insert 2 into stack and maxEle = 5.
    • Number to be Inserted: 1, Stack is not empty, 1< maxEle, insert 1 into stack and maxEle = 5.

    Pop() :

    • Initially the maximum element maxEle in the stack is 5.
    • Number removed: 1, Since 1 is less than maxEle just pop 1. maxEle=5.
    • Number removed: 2, 2<maxEle, so number removed is 2 and maxEle is still equal to 5.
    • Number removed: 7, 7> maxEle, original number is maxEle which is 5 and new maxEle = 2*5 – 7 = 3.

    Implementation:

    C++

    #include <bits/stdc++.h>

    using namespace std;

    struct MyStack {

        stack<int> s;

        int maxEle;

        void getMax()

        {

            if (s.empty())

                cout << "Stack is emptyn";

            else

                cout << "Maximum Element in the stack is: "

                     << maxEle << "n";

        }

        void peek()

        {

            if (s.empty()) {

                cout << "Stack is empty ";

                return;

            }

            int t = s.top();

            cout << "Top Most Element is: ";

            (t > maxEle) ? cout << maxEle : cout << t;

        }

        void pop()

        {

            if (s.empty()) {

                cout << "Stack is emptyn";

                return;

            }

            cout << "Top Most Element Removed: ";

            int t = s.top();

            s.pop();

            if (t > maxEle) {

                cout << maxEle << "n";

                maxEle = 2 * maxEle - t;

            }

            else

                cout << t << "n";

        }

        void push(int x)

        {

            if (s.empty()) {

                maxEle = x;

                s.push(x);

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

                return;

            }

            if (x > maxEle) {

                s.push(2 * x - maxEle);

                maxEle = x;

            }

            else

                s.push(x);

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

        }

    };

    int main()

    {

        MyStack s;

        s.push(3);

        s.push(5);

        s.getMax();

        s.push(7);

        s.push(19);

        s.getMax();

        s.pop();

        s.getMax();

        s.pop();

        s.peek();

        return 0;

    }

    Java

    import java.util.*;

    class GFG

    {

    static class MyStack

    {

        Stack<Integer> s = new Stack<Integer>();

        int maxEle;

        void getMax()

        {

            if (s.empty())

                System.out.print("Stack is emptyn");

            else

                System.out.print("Maximum Element in" +

                            "the stack is: "+maxEle + "n");

        }

        void peek()

        {

            if (s.empty())

            {

                System.out.print("Stack is empty ");

                return;

            }

            int t = s.peek();

            System.out.print("Top Most Element is: ");

            if(t > maxEle)

                System.out.print(maxEle);

            else

                System.out.print(t);

        }

        void pop()

        {

            if (s.empty())

            {

                System.out.print("Stack is emptyn");

                return;

            }

            System.out.print("Top Most Element Removed: ");

            int t = s.peek();

            s.pop();

            if (t > maxEle)

            {

                System.out.print(maxEle + "n");

                maxEle = 2 * maxEle - t;

            }

            else

                System.out.print(t + "n");

        }

        void push(int x)

        {

            if (s.empty())

            {

                maxEle = x;

                s.push(x);

                System.out.print("Number Inserted: " + x + "n");

                return;

            }

            if (x > maxEle)

            {

                s.push(2 * x - maxEle);

                maxEle = x;

            }

            else

                s.push(x);

            System.out.print("Number Inserted: " + x + "n");

        }

    };

    public static void main(String[] args)

    {

        MyStack s = new MyStack();

        s.push(3);

        s.push(5);

        s.getMax();

        s.push(7);

        s.push(19);

        s.getMax();

        s.pop();

        s.getMax();

        s.pop();

        s.peek();

        }

    }

    Python 3

    class Node:

        def __init__(self, value):

            self.value = value

            self.next = None

        def __str__(self):

            return "Node({})".format(self.value)

        __repr__ = __str__

    class Stack:

        def __init__(self):

            self.top = None

            self.count = 0

            self.maximum = None

        def __str__(self):

            temp=self.top

            out=[]

            while temp:

                out.append(str(temp.value))

                temp=temp.next

            out='n'.join(out)

            return ('Top {} nnStack :n{}'.format(self.top,out))

        __repr__=__str__

        def getMax(self):

            if self.top is None:

                return "Stack is empty"

            else:

                print("Maximum Element in the stack is: {}" .format(self.maximum))

        def isEmpty(self):

            if self.top == None:

                return True

            else:

                return False

        def __len__(self):

            self.count = 0

            tempNode = self.top

            while tempNode:

                tempNode = tempNode.next

                self.count+=1

            return self.count

        def peek(self):

            if self.top is None:

                print ("Stack is empty")

            else:   

                if self.top.value > self.maximum:

                    print("Top Most Element is: {}" .format(self.maximum))

                else:

                    print("Top Most Element is: {}" .format(self.top.value))

        def push(self,value):

            if self.top is None:

                self.top = Node(value)

                self.maximum = value

            elif value > self.maximum :

                temp = (2 * value) - self.maximum

                new_node = Node(temp)

                new_node.next = self.top

                self.top = new_node

                self.maximum = value

            else:

                new_node = Node(value)

                new_node.next = self.top

                self.top = new_node

            print("Number Inserted: {}" .format(value))

        def pop(self):

            if self.top is None:

                print( "Stack is empty")

            else:

                removedNode = self.top.value

                self.top = self.top.next

                if removedNode > self.maximum:

                    print ("Top Most Element Removed :{} " .format(self.maximum))

                    self.maximum = ( ( 2 * self.maximum ) - removedNode )

                else:

                    print ("Top Most Element Removed : {}" .format(removedNode))

    stack = Stack()

    stack.push(3)

    stack.push(5)

    stack.getMax()

    stack.push(7)

    stack.push(19)

    stack.getMax()    

    stack.pop()

    stack.getMax()

    stack.pop()

    stack.peek()

    C#

    using System;

    using System.Collections.Generic;

    class GFG

    {

    public class MyStack

    {

        public Stack<int> s = new Stack<int>();

        public int maxEle;

        public void getMax()

        {

            if (s.Count == 0)

                Console.Write("Stack is emptyn");

            else

                Console.Write("Maximum Element in" +

                            "the stack is: "+maxEle + "n");

        }

        public void peek()

        {

            if (s.Count == 0)

            {

                Console.Write("Stack is empty ");

                return;

            }

            int t = s.Peek();

            Console.Write("Top Most Element is: ");

            if(t > maxEle)

                Console.Write(maxEle);

            else

                Console.Write(t);

        }

        public void pop()

        {

            if (s.Count == 0)

            {

                Console.Write("Stack is emptyn");

                return;

            }

            Console.Write("Top Most Element Removed: ");

            int t = s.Peek();

            s.Pop();

            if (t > maxEle)

            {

                Console.Write(maxEle + "n");

                maxEle = 2 * maxEle - t;

            }

            else

                Console.Write(t + "n");

        }

        public void push(int x)

        {

            if (s.Count == 0)

            {

                maxEle = x;

                s.Push(x);

                Console.Write("Number Inserted: " + x + "n");

                return;

            }

            if (x > maxEle)

            {

                s.Push(2 * x - maxEle);

                maxEle = x;

            }

            else

                s.Push(x);

            Console.Write("Number Inserted: " + x + "n");

        }

    };

    public static void Main(String[] args)

    {

        MyStack s = new MyStack();

        s.push(3);

        s.push(5);

        s.getMax();

        s.push(7);

        s.push(19);

        s.getMax();

        s.pop();

        s.getMax();

        s.pop();

        s.peek();

    }

    }

    Javascript

    <script>

        let s = [];

        let maxEle;

        function getMax()

        {

            if (s.length == 0)

                document.write("Stack is empty" + "</br>");

            else

                document.write("Maximum Element in " +

                            "the stack is: "+maxEle + "</br>");

        }

        function peek()

        {

            if (s.length == 0)

            {

                document.write("Stack is empty ");

                return;

            }

            let t = s[s.length - 1];

            document.write("Top Most Element is: ");

            if(t > maxEle)

                document.write(maxEle);

            else

                document.write(t);

        }

        function pop()

        {

            if (s.length == 0)

            {

                document.write("Stack is empty" + "</br>");

                return;

            }

            document.write("Top Most Element Removed: ");

            let t = s[s.length - 1];

            s.pop();

            if (t > maxEle)

            {

                document.write(maxEle + "</br>");

                maxEle = 2 * maxEle - t;

            }

            else

                document.write(t + "</br>");

        }

        function push(x)

        {

            if (s.length == 0)

            {

                maxEle = x;

                s.push(x);

                document.write("Number Inserted: " + x + "</br>");

                return;

            }

            if (x > maxEle)

            {

                s.push(2 * x - maxEle);

                maxEle = x;

            }

            else

                s.push(x);

            document.write("Number Inserted: " + x + "</br>");

        }

        push(3);

        push(5);

        getMax();

        push(7);

        push(19);

        getMax();

        pop();

        getMax();

        pop();

        peek();

    </script>

    Output

    Number Inserted: 3
    Number Inserted: 5
    Maximum Element in the stack is: 5
    Number Inserted: 7
    Number Inserted: 19
    Maximum Element in the stack is: 19
    Top Most Element Removed: 19
    Maximum Element in the stack is: 7
    Top Most Element Removed: 7
    Top Most Element is: 5

    Complexity Analysis:

    • Time Complexity: O(1) 
    • Auxiliary Space: O(1) 

    Last Updated :
    03 Nov, 2022

    Like Article

    Save Article

    Hello Everyone!

    In this tutorial, we will learn about the working of a Stack and Finding it’s Maximum element in the C++ programming language.

    To understand the basic functionality of the Stack, we will recommend you to visit the Stack Data Structure, where we have explained this concept in detail from scratch.

    For a better understanding of its implementation, refer to the well-commented C++ code given below.

    Code:

    #include <iostream>
    #include <bits/stdc++.h>
    
    using namespace std;
    
    //Function to print the Maximum element in the stack
    void findMax(stack<int> s)
    {
        int m = s.top(); //initialization
    
        int a;
    
        while (!s.empty())
        {
            a = s.top();
    
            if (m < a)
                m = a; //Storing the maximum element in m
    
            s.pop(); //removing the topmost element to bring next element at the top
        }
    
        cout << "nnThe maximum element of the Stack is: " << m << endl;
    }
    
    //Function to print the elements of the stack
    void show(stack<int> s)
    {
        while (!s.empty())
        {
            cout << "  " << s.top(); //printing the topmost element
            s.pop();                 //removing the topmost element to bring next element at the top
        }
    
        cout << endl;
    }
    
    int main()
    {
        cout << "nnWelcome to Studytonight :-)nnn";
        cout << " =====  Program to Find the Maximum element in the Stack, in CPP  ===== nn";
    
        int i;
    
        //Stack declaration (stack of integers)
        stack<int> s;
    
        //Filling the elements by using the push() method.
        cout << "Filling the Stack in LIFO order using the push() method:"; //LIFO= Last In First Out
    
        s.push(4);
        s.push(2);
        s.push(20);
        s.push(12);
        s.push(52);
        s.push(14);
    
        cout << "nnThe elements of the Stack in LIFO order are: ";
        show(s);
    
        findMax(s); //to find the max element
    
        cout << "nnn";
    
        return 0;
    }
    

    Output:

    C++ Stack Max

    We hope that this post helped you develop a better understanding of the concept of Stack and its implementation in C++. For any query, feel free to reach out to us via the comments section down below.

    Keep Learning : )



    Edit:

    without iterating over the Stack

    does not actually prohibit all iteration. Rather, the question only prohibits doing the simple

    for (Integer i : lifo)
    

    Thus, this solution satisfies the question’s limitations.


    Just empty a copy of the stack. pop each of the elements from the copy, checking for max against an integer all the while.

    Stack<Integer> lifoCopy = (Stack<Integer>) lifo.clone();
    int max = Integer.MIN_VALUE;
    
    while (!lifoCopy.isEmpty())
    {
        max = Math.max(lifoCopy.pop(), max);
    }
    
    System.out.println("max=" + max.toString());
    

    This will work for you in O(n) time even if your interviewers decide to be more restrictive and not allow more built in functions (max, min, sort, etc.).

    Additionally, if you need to have the original unharmed, but can’t use clone, you can do so with an extra stack:

    Stack<Integer> reverseLifo = new Stack<Integer>();
    int max = Integer.MIN_VALUE;
    
    while (!lifo.isEmpty())
    {
        int val = lifo.pop();
    
        max = Math.max(val, max);
    
        reverseLifo.push(val);
    }
    
    while (!reverseLifo.isEmpty())
    {
        lifo.push(reverseLifo.pop());
    }
    
    System.out.println("max=" + max.toString());
    

    Finally, this assumes that comparison against a temp variable is acceptable. If no comparison is allowed at all, then this solution in conjunction with this method will work.

    Алгоритмы прекрасны тем, что они могут решать сложные проблемы удивительно простыми способами. Однако полезность алгоритма проявляется и тогда, когда он предлагает более эффективный (или интересный) способ решения достаточно простой задачи.

    Предположим, мы хотим найти наибольшее число в стеке, полностью состоящем из целых чисел. Как бы мы это сделали?

    Мы должны помнить, что максимальное значение в стеке потенциально может меняться каждый раз, когда мы выталкиваем и выталкиваем из стека. Это особенно заметно в отсортированном стеке с различными значениями, где максимальное значение всегдаизменяется.

    Мы не хотим переопределять максимум каждый раз, когда мы помещаем и выталкиваем в стек, если мы можем помочь. И если мы это сделаем, мы не хотим, чтобы процесс поиска был дорогостоящим.

    Наивное решение

    Ваш первый инстинкт поиска максимального значения в стеке, вероятно, отражен в приведенном ниже коде Ruby, который создает простой класс Stack с добавленным методом «max».

    class Stack
      def initialize
        @stack = []
        @max = nil
      end
      
      def push(val) 
        @stack.push(val)
        @max = max
      end
      
      def pop
        @stack.pop
        @max = max
      end
      
      def peek(index)
        raise ArgumentError unless ([email protected]).include?(index)
        @stack[index]
      end
      def max 
        return nil if @stack.empty? 
        max = peek(0)
        @stack.length.times do |i|
          max = @stack[i] if max < @stack[i]
        end
        max
      end
      
    end

    Поиск максимума таким образом работает, но не слишком эффективно. Временная сложность метода «max» — это линейное время, или O(n), поскольку нам приходится просматривать весьстек каждый раз, когда мы хотим найти максимальное значение. Мы также запускаем этот алгоритм O(n) каждый раз, когда мы нажимаем и выталкиваем! Там должен быть лучший способ.

    Мы должны стремиться к постоянному времени, или O(1), так как это золотой стандарт для поиска в целом. Но как нам достичь этой цели?

    Умное решение

    К счастью, есть алгоритм, который помогает нам быстро находить и отслеживать максимум стека по мере его создания. Этот алгоритм показан в коде Ruby ниже:

    class Stack
      def initialize
        @stack = []
        @max_stack = [] # a second stack!
      end
      
      def push(val) 
        @stack.push(val)
        if @max_stack.empty? || val > peek_max
          @max_stack.push(val) 
        end
      end
      
      def pop
        last = @stack.pop
        @max_stack.pop if last == peek_max
      end
      
      def peek(index)
        raise ArgumentError unless ([email protected]).include?(index)
        @stack[index]
      end
      
      def peek_max
        @max_stack[-1]
      end
      
      def inspect 
        @stack  
      end
      def max 
        peek_max
      end
      
    end

    Этот алгоритм на самом деле основан на использовании двухстеков: stack и max_stack.stack отслеживают целые числа, а max_stack отслеживает максимальные значения при построении стека.

    Когда мы нажимаем на stack и обнаруживаем, что переданное значение больше, чем значение, расположенное вверху max_stack, мы также нажимаем это значение на max_stack.

    Когда мы извлекаем из stack и обнаруживаем, что извлеченное значение совпадает со значением, расположенным вверху max_stack, мы также извлекаем последнее значение из max_stack. Значение должно быть добавлено в оба стека вместе, поэтому они должны быть удалены вместе.

    Наконец, получить максимальное значение стека — это просто посмотреть на самое верхнее значение max_stack с помощью метода peek_max. Нам удалось найти максимум за время O(1) простым поиском!

    Вывод

    Как и все алгоритмы, этот алгоритм «двойного стека» не идеален. Предполагается, что стек изначально пуст, что позволяет нам отслеживать максимальное значение по мере создания стека. Если стек уже инициализирован значениями и мы еще не отслеживаем максимальное значение, мы должны сделать одно из следующих действий:

    • Перестройте стек, создав стек максимальных значений, поскольку обычный стек перестраивается.
    • Используйте метод max в «наивном» решении или другой метод, не основанный на построении стека.

    Кроме того, при использовании алгоритма двойного стека возрастает сложность пространства, поскольку нам нужен совершенно новый стек для отслеживания максимальных значений. Вам решать, стоит ли функциональность O(1) push, pop и max lookup дополнительного необходимого пространства.

    Тем не менее, как и все алгоритмы, этот, безусловно, полезно держать в наборе инструментов вашего программиста.

    Предоставлено Interview Cake.

    Подскажу сперва идею. Сделайте стек в котором хранятся как значения, так и максимумы. Например:

    команда  стек                          результат
    pop      []                            error
    pop      []                            error
    push 4   [(4, 4)]
    push -5  [(4, 4), (-5, 4)]
    push 7   [(4, 4), (-5, 4), (7, 7)]
    pop      [(4, 4), (-5, 4)]
    pop      [(4, 4)]
    get_max  [(4, 4)]                      4
    pop      []
    get_max  []                            None
    

    Как записывать и использовать максимумы догадайтесь сами.

    P.S. Пристально поглядев на условия можно понять, что первое значение из пары не используется. То есть вам достаточно хранить только максимумы в стеке. Вот так:

    команда  стек         результат
    pop      []           error
    pop      []           error
    push 4   [4]
    push -5  [4, 4]
    push 7   [4, 4, 7]
    pop      [4, 4]
    pop      [4]
    get_max  [4]          4
    pop      []
    get_max  []           None
    

    Стек избыточен в этой конкретной реализации: он хранит и значения и максимумы. Зато у него нормальный интерфейс:

    class StackMaxEffective:
        def __init__(self):
            self.stack_ = []
    
        def __bool__(self):
            return bool(self.stack_)
    
        def push(self, item):
            if self.stack_:
                new_max = max(item, self.stack_[-1][1])
            else:
                new_max = item
            self.stack_.append((item, new_max))
    
        def pop(self):
            return self.stack_.pop()[0]
    
        def get_max(self):
            return self.stack_[-1][1]
    
    
    s = StackMaxEffective()
    for _ in range(int(input())):
        cmd = input().split()
        if cmd[0] == 'pop':
            if s:
                s.pop()
            else:
                print('error')
        if cmd[0] == 'push':
            s.push(int(cmd[1]))
        if cmd[0] == 'get_max':
            if s:
                print(s.get_max())
            else:
                print('None')
    

    Добавить комментарий