Hãy giả sử ngăn xếp mà chúng ta sẽ làm việc là:
6 , minvalue=2
2 , minvalue=2
5 , minvalue=3
3 , minvalue=3
9 , minvalue=7
7 , minvalue=7
8 , minvalue=8
Trong biểu diễn trên, ngăn xếp chỉ được xây dựng bởi giá trị bên trái, [giá trị tối thiểu] của giá trị bên phải chỉ được viết cho mục đích minh họa sẽ được lưu trữ trong một biến.
Vấn đề thực tế là khi giá trị là giá trị minimun nhận được bị loại bỏ tại thời điểm đó làm thế nào chúng ta có thể biết đâu là phần tử tối thiểu tiếp theo mà không cần lặp qua ngăn xếp.
Ví dụ như trong ngăn xếp của chúng tôi khi 6 get xuất hiện, chúng tôi biết rằng, đây không phải là phần tử tối thiểu vì phần tử tối thiểu là 2, vì vậy chúng tôi có thể loại bỏ điều này một cách an toàn mà không cần cập nhật giá trị tối thiểu của chúng tôi.
Nhưng khi bật 2, chúng ta có thể thấy rằng giá trị nhỏ nhất hiện tại là 2 và nếu giá trị này xuất hiện thì chúng ta cần cập nhật giá trị tối thiểu thành 3.
Điểm 1:
Bây giờ nếu bạn quan sát kỹ, chúng ta cần tạo minvalue = 3 từ trạng thái cụ thể này [2, minvalue = 2]. hoặc nếu bạn đi depperin ngăn xếp, chúng tôi cần tạo minvalue = 7 từ trạng thái cụ thể này [3, minvalue = 3] hoặc nếu bạn đi nhiều depper hơn trong ngăn xếp thì chúng tôi cần tạo minvalue = 8 từ trạng thái cụ thể này [7, minvalue = 7]
Bạn có nhận thấy điểm chung trong cả 3 trường hợp trên là giá trị mà chúng ta cần tạo ra phụ thuộc vào hai biến cả hai đều bằng nhau. Chính xác. Tại sao điều này lại xảy ra bởi vì khi chúng tôi đẩy một số phần tử nhỏ hơn giá trị tối thiểu hiện tại, thì về cơ bản chúng tôi đẩy phần tử đó vào ngăn xếp và cập nhật cùng một số trong giá trị tối thiểu cũng vậy.
Điểm 2:
Vì vậy, về cơ bản chúng ta đang lưu trữ bản sao của cùng một số một lần trong ngăn xếp và một lần trong biến giá trị tối thiểu. Chúng ta cần tập trung vào việc tránh trùng lặp này và lưu trữ dữ liệu hữu ích nào đó trong ngăn xếp hoặc giá trị tối thiểu để tạo ra mức tối thiểu trước đó như được hiển thị trong các TRƯỜNG HỢP ở trên.
Hãy tập trung vào những gì chúng ta nên lưu trữ trong ngăn xếp khi giá trị cần lưu trữ trong lần đẩy nhỏ hơn giá trị minmumvalue. Hãy đặt tên cho biến này là y, vì vậy bây giờ ngăn xếp của chúng ta sẽ trông giống như sau:
6 , minvalue=2
y1 , minvalue=2
5 , minvalue=3
y2 , minvalue=3
9 , minvalue=7
y3 , minvalue=7
8 , minvalue=8
Tôi đã đổi tên chúng thành y1, y2, y3 để tránh nhầm lẫn rằng tất cả chúng sẽ có cùng giá trị.
Điểm 3:
Bây giờ, hãy thử tìm một số ràng buộc trên y1, y2 và y3. Bạn có nhớ chính xác khi nào chúng ta cần cập nhật giá trị tối thiểu trong khi thực hiện pop (), chỉ khi chúng ta đã bật phần tử bằng giá trị tối thiểu. Nếu chúng tôi bật thứ gì đó lớn hơn giá trị tối thiểu thì chúng tôi không phải cập nhật giá trị tối thiểu. Vì vậy, để kích hoạt cập nhật giá trị tối thiểu, y1, y2 & y3 phải nhỏ hơn giá trị tối thiểu tương ứng. [Chúng tôi sử dụng bình đẳng để tránh trùng lặp [Point2]] vì vậy ràng buộc là [y <minValue].
Bây giờ chúng ta hãy quay lại điền y, chúng ta cần tạo ra một số giá trị và đặt y tại thời điểm đẩy, hãy nhớ. Hãy lấy giá trị sắp đẩy là x nhỏ hơn Giá trị hiện tại và giá trị mà chúng ta thực sự sẽ đẩy trong ngăn xếp là y. Vì vậy, một điều hiển nhiên là newMinValue = x và y <newMinvalue.
Bây giờ chúng ta cần tính toán y (hãy nhớ y có thể là một số bất kỳ nhỏ hơn newMinValue (x), vì vậy chúng ta cần tìm một số có thể đáp ứng ràng buộc của chúng ta) với sự trợ giúp của giá trị trước và x (giá trị mới).
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].
Vì vậy, tại thời điểm đẩy x nếu nó nhỏ hơn giá trị trước thì chúng ta đẩy y [2 * x-prevMinValue] và cập nhật newMinValue = x.
Và tại thời điểm bật lên nếu ngăn xếp chứa thứ gì đó nhỏ hơn minValue thì đó là trình kích hoạt của chúng tôi để cập nhật minVAlue. Chúng ta phải tính toán giá trị trước khi thu được từ curMinValue và y. y = 2 * curMinValue - prevMinValue [Đã chứng minh] prevMinVAlue = 2 * curMinvalue - y.
2 * curMinValue - y là số mà chúng ta cần cập nhật ngay bây giờ lên giá trị trước.
Mã cho cùng một logic được chia sẻ dưới đây với độ phức tạp O (1) thời gian và O (1) không gian.
// 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;
}