【C++】LeetCode 初级 - 最小栈 (推荐一个不使用stack的方法)

设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) – 将元素 x 推入栈中。
pop() – 删除栈顶的元素。
top() – 获取栈顶元素。
getMin() – 检索栈中的最小元素。

首先使用STL库 stack,有两种思路
1.用两个栈来记录,一个记录所有的值,一个只记录最小值,
push——第一个栈所有都push,第二栈只push和当前一样或者比当前小的值
pop的时候如果第一个栈和第二个栈的数字相等,两个都执行pop,否则只pop第二个

2.第一个思路的优化版本,只用一个栈,和一个int
在每一次push min value的时候,多插一次上一次的值,
在每一次pop 的时候如果 pop的是最小值,那么就用一下个当做最小值,病且也把这个值pop出去。

可以参考这个人的博客
https://www.cnblogs.com/lightwindy/p/8512214.html

下面是我的思路:
用了一个数组来创建最小堆, 用链表管理他们直接的循序,比较复杂有兴趣的可以看一下,如果有什么建议可以留言给我

class MinStack {
public:
	/** initialize your data structure here. */

	
	/** 最小栈里面不仅仅需要存数据,还要动态的存他们在这个数组中的位置 */
	struct Info{  
		int data;
		int pos;
	};

	//一个链表模拟一个栈,每一个节点上记录了一个最小堆上元素的地址, 
	//这样做的目的是
	struct LinkNode{
		Info *ptr;
		LinkNode* next;
		LinkNode(Info* _pos) : ptr(_pos), next(NULL){}
	};

	LinkNode *head;

	vector<Info*> stack;

	MinStack() :head(NULL) {

	}

    ~MinStack(){
		//释放内存
        while(head != NULL){
            LinkNode* t = head;
            head = head -> next;
            delete t;
        }
    }
	void push(int x) {
		//插入到最小堆中,放到最后
		Info *info = new Info();
		info->data = x;
		stack.push_back(info);  
		int pos = stack.size() - 1;

		//向上开始整理堆,保证堆顶元素最小
		int f = pos % 2 == 0 ? (pos - 2) / 2 : (pos - 1) / 2;
		while (f >= 0 && stack[pos]->data < stack[f]->data){
			stack[f]->pos = pos;  //动态的改变 节点上的位置信息, father节点的位置要向下移
			Info* temp = stack[pos]; stack[pos] = stack[f]; stack[f] = temp;  //注意这里交换的是地址!!!
			pos = f;  
			f = pos % 2 == 0 ? (pos - 2) / 2 : (pos - 1) / 2;  //计算心father
		}
		info->pos = pos;

		//update 链表
		LinkNode* node = new LinkNode(info);

		node->next = head;
		head = node;
	}

	void pop() {
		if (head == NULL) return;
		int pos = head->ptr->pos;

		//exchange with the last one
		int last = stack.size() - 1;
		//交换当前移除堆的元素 和 堆底的元素 准备调整堆
		Info* temp = stack[pos]; stack[pos] = stack[last]; stack[last] = temp;
		stack[pos]->pos;

		stack.pop_back();
		
		//移除链表 释放内存
		LinkNode* t = head; head = head->next;
	
        delete t;
		//向下调整堆
		while (pos * 2 + 1 < stack.size() || pos * 2 + 2 < stack.size()){
			if (pos * 2 + 2 < stack.size()){
				if (stack[pos * 2 + 2]->data < stack[pos * 2 + 1]->data){
					if (stack[pos]->data > stack[pos * 2 + 2]->data){
						Info* temp = stack[pos]; stack[pos] = stack[pos * 2 + 2]; stack[pos * 2 + 2] = temp;
						stack[pos]->pos = pos; stack[pos * 2 + 2]->pos = pos * 2 + 2;
						pos = pos * 2 + 2;
					}
					else break;
				}
				else{
					if (stack[pos]->data > stack[pos * 2 + 1]->data){
						Info* temp = stack[pos]; stack[pos] = stack[pos * 2 + 1]; stack[pos * 2 + 1] = temp;
						stack[pos]->pos = pos; stack[pos * 2 + 1]->pos = pos * 2 + 1;
						pos = pos * 2 + 1;
					}
					else break;
				}

			}
			else if (pos * 2 + 1 < stack.size()){
				if (stack[pos]->data > stack[pos * 2 + 1]->data){
					Info* temp = stack[pos]; stack[pos] = stack[pos * 2 + 1]; stack[pos * 2 + 1] = temp;
					stack[pos]->pos = pos; stack[pos * 2 + 1]->pos = pos * 2 + 1;
					pos = pos * 2 + 1;
				}
				else break;
			}
		}

	}

	int top() {
		return head->ptr->data;
	}

	int getMin() {
		if (stack.size() == 0) return 0;
		return stack[0]->data;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值