Припустимо, стек, над яким ми будемо працювати, полягає в наступному:
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.
Точка1:
Тепер, якщо ви уважно спостерігаєте, нам потрібно генерувати мінімальне значення = 3 з цього стану [2, minvalue = 2]. або якщо ви перейдете депернізувати стек, нам потрібно генерувати мінімальне значення = 7 з цього конкретного стану [3, minvalue = 3] або якщо ви переходите в стек більше деперсів, то нам потрібно генерувати minvalue = 8 з цього конкретного стану [7, minvalue = 7]
Ви помітили щось спільне у всіх вищезгаданих 3 випадках, значення, яке нам потрібно створити, залежить від двох змінних, які обидва рівні. Правильно. Чому це відбувається тому, що коли ми натискаємо на якийсь елемент менший за поточне мінімальне значення, ми, як правило, висуваємо цей елемент у стеку і також оновлюємо те саме число в minvalue.
Точка 2:
Таким чином, ми в основному зберігаємо дублікат одного і того ж числа один раз у стеці та один раз у змінній minvalue. Нам потрібно зосередитись на тому, щоб уникнути цього дублювання і зберігати щось корисне в стеку або в мінімальному значенні, щоб генерувати попередній мінімум, як показано в CASES вище.
Давайте зосередимось на тому, що нам потрібно зберігати в стеці, коли значення для зберігання в push менше, ніж мінімальне значення. Назвемо цю змінну 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, y1, y2 & y3 повинно бути меншим, ніж відповідне minvalue. [Ми пропонуємо рівність, щоб уникнути дублювання [Point2]], тому обмеження є [y <minValue].
Тепер повернемося, щоб заповнити y, нам потрібно генерувати якесь значення і поставити y на момент натиску, пам’ятайте. Візьмемо значення, яке приходить для push, щоб бути x, яке менше, ніж prevMinvalue, і значення, яке ми насправді будемо натискати в стеку, бути 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. Ми повинні обчислити prevMinValue з curMinValue і y. 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;
}