力扣算法100个实际应用场景(7)-最小栈实现
【算法与实践结合的最小栈应用】本项目通过LeetCode 155题展示最小栈的工程价值,实现O(1)时间复杂度获取栈最小值。采用双栈结构(主栈+辅助栈)或节点存储最小值两种方案,在数据库优化、游戏AI、系统监控等场景有广泛应用。代码示例包含完整的最小栈实现及股票监控系统应用,演示如何实时跟踪价格波动并快速获取历史最低价。核心思想是通过空间换时间,为算法学习提供真实工程案例参考,破除"刷题
项目简介
这个项目展示了100道经典LeetCode算法题在实际工程中的应用场景,帮助学员理解算法的实用价值,建立理论与实践的桥梁。
核心目标
-
让算法学习更有意义,不再是纸上谈兵
-
帮助面试者理解算法背后的工程价值
-
为工程师提供算法选择的实际参考
这是栈/队列应用的第七篇:最小栈实现
视频讲解与源码领取:你不光要刷力扣,还要懂力扣算法100个实际使用场景(上)
实际应用
在数据库查询优化、编译器优化、游戏AI决策中,经常需要维护一个栈结构,同时能够快速获取当前栈中的最小值。这在回溯算法、状态管理、性能监控等场景中非常有用。
最小栈结构示意图
对应算法
LeetCode题目: 155. 最小栈
核心思想:
LeetCode 155要求设计一个栈,支持push、pop、top和getMin操作,且所有操作都是O(1)时间复杂度。解决方案使用辅助栈来维护最小值:
-
双栈设计: 主栈存储所有元素,辅助栈存储每个状态下的最小值
-
同步操作: push时同时更新两个栈,pop时同时弹出
-
最小值维护: 辅助栈顶始终保持当前主栈的最小值
-
空间优化: 可以只在需要时才向辅助栈添加元素
算法精髓:
通过空间换时间,用额外的栈空间来维护最小值信息,实现O(1)的最小值查询。
应用领域
-
股票交易系统 - 实时维护当前时间窗口内的最低价格
-
游戏排行榜 - 维护玩家分数历史的最低点
-
系统监控 - 跟踪服务器性能指标的最小值
代码示例
// 最小栈的高级实现 - 支持多种优化策略
class MinStack {
private:
struct StackNode {
int value;
int min_value; // 到当前位置为止的最小值
StackNode(int val, int min_val) : value(val), min_value(min_val) {}
};
stack<StackNode> main_stack;
public:
/**
* @brief 压入元素
* @param x 要压入的值
*/
void push(int x) {
// 计算新的最小值
int new_min = main_stack.empty() ? x : min(x, main_stack.top().min_value);
// 压入新节点
main_stack.push(StackNode(x, new_min));
cout << "压入 " << x << ",当前最小值: " << new_min << endl;
}
/**
* @brief 弹出栈顶元素
*/
void pop() {
if (main_stack.empty()) {
cout << "栈为空,无法弹出" << endl;
return;
}
int popped_value = main_stack.top().value;
main_stack.pop();
cout << "弹出 " << popped_value;
if (!main_stack.empty()) {
cout << ",当前最小值: " << main_stack.top().min_value;
} else {
cout << ",栈已空";
}
cout << endl;
}
/**
* @brief 获取栈顶元素
* @return 栈顶元素值
*/
int top() {
if (main_stack.empty()) {
throw runtime_error("栈为空");
}
return main_stack.top().value;
}
/**
* @brief 获取栈中最小元素
* @return 最小元素值
*/
int getMin() {
if (main_stack.empty()) {
throw runtime_error("栈为空");
}
return main_stack.top().min_value;
}
/**
* @brief 获取栈的大小
*/
int size() const {
return main_stack.size();
}
/**
* @brief 检查栈是否为空
*/
bool empty() const {
return main_stack.empty();
}
/**
* @brief 打印栈的详细状态
*/
void printStack() {
if (main_stack.empty()) {
cout << "栈为空" << endl;
return;
}
cout << "=== 栈状态 ===" << endl;
stack<StackNode> temp = main_stack;
vector<StackNode> nodes;
// 将所有元素取出
while (!temp.empty()) {
nodes.push_back(temp.top());
temp.pop();
}
// 从栈顶到栈底打印
cout << "位置 值 最小值" << endl;
for (int i = nodes.size() - 1; i >= 0; --i) {
cout << setw(3) << (nodes.size() - i) << " "
<< setw(3) << nodes[i].value << " "
<< setw(6) << nodes[i].min_value << endl;
}
cout << "==============" << endl;
}
};
// 空间优化版本的最小栈
class OptimizedMinStack {
private:
stack<int> main_stack;
stack<int> min_stack; // 只存储真正的最小值变化点
public:
void push(int x) {
main_stack.push(x);
// 只有当新值小于等于当前最小值时,才压入最小值栈
if (min_stack.empty() || x <= min_stack.top()) {
min_stack.push(x);
}
}
void pop() {
if (main_stack.empty()) return;
int popped = main_stack.top();
main_stack.pop();
// 如果弹出的是最小值,也要从最小值栈中弹出
if (!min_stack.empty() && popped == min_stack.top()) {
min_stack.pop();
}
}
int top() {
return main_stack.top();
}
int getMin() {
return min_stack.top();
}
/**
* @brief 获取空间使用效率
* @return 最小值栈的空间占用比例
*/
double getSpaceEfficiency() {
if (main_stack.empty()) return 0.0;
return (double)min_stack.size() / main_stack.size();
}
};
// 应用示例:股票价格监控
class StockPriceMonitor {
private:
MinStack price_history;
string stock_symbol;
public:
StockPriceMonitor(const string& symbol) : stock_symbol(symbol) {}
/**
* @brief 记录新的股票价格
* @param price 股票价格(以分为单位避免浮点数问题)
*/
void recordPrice(int price) {
price_history.push(price);
cout << stock_symbol << " 新价格: " << (price / 100.0)
<< " 元,历史最低: " << (price_history.getMin() / 100.0) << " 元" << endl;
}
/**
* @brief 获取当前价格
*/
double getCurrentPrice() {
return price_history.top() / 100.0;
}
/**
* @brief 获取历史最低价
*/
double getLowestPrice() {
return price_history.getMin() / 100.0;
}
/**
* @brief 检查是否创造了新低
*/
bool isNewLow() {
return price_history.top() == price_history.getMin();
}
/**
* @brief 生成价格报告
*/
void generateReport() {
cout << "\n=== " << stock_symbol << " 价格报告 ===" << endl;
cout << "当前价格: " << getCurrentPrice() << " 元" << endl;
cout << "历史最低: " << getLowestPrice() << " 元" << endl;
cout << "价格记录数: " << price_history.size() << endl;
if (isNewLow()) {
cout << "🔻 当前价格为历史新低!" << endl;
}
cout << "============================" << endl;
}
};
更多推荐
所有评论(0)