算法模板-----栈和队列

Posted 栋次大次

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法模板-----栈和队列相关的知识,希望对你有一定的参考价值。

目录

min-stack
evaluate-reverse-polish-notation
decode-string
binary-tree-inorder-traversal
clone-graph
number-of-islands
largest-rectangle-in-histogram
implement-queue-using-stacks
01-matrix

特点是先入后出,利用这个特点可以保存一些临时数据,之后用到再以此弹出,常用于DFS深度搜索。

队列是先用先出,常用于BFS广度搜索,类似层次遍历。

下面根据一些例题来学习下栈的用法。

min-stack

设计一个支持push、pop、top操作,并且能在常数时间内检索到最小元素的栈。
用两个栈实现,一个栈始终保证最小值在顶部。

class MinStack
private: 
	stack<int> normalStack;
	stack<int> min_stack;
public:
	MinStack()
		min_stack.push(INT_MAX);
	
	void push(int x)
		normalStack.push(x);
		min_stack.push(min_stack.top(), x);
	
	void pop()
		normalStack.pop();
		min_stack.pop();
	
	int top()
		return normalStack.top();
	
	int getMin()
		return min_stack.top();
	
;

evaluate-reverse-polish-notation

根据逆波兰表达式求解,逆波兰表达式 > 输入[“2”, “1”, “+”, “3”, “*”] > 输出:9 ,((2+1)*3) = 9
通过栈保存原来的元素,遇到表达式弹出运算,再压入结果,重复这个过程。

int evalRPN(vector<string>& token)
	if(tokens.size() == 0) return 0;
	
	stack<int> res;
	for(string s : tokens)
		if(s != "+" && s != "-" && s != "*" && s != "/")
			res.push(stoi(s));
		else
			int b = res.top();
			res.pop();
			int a = res.top();
			res.pop();
			if(s == '+') res.push(a + b);
			if(s == '-') res.push(a - b);
			if(s == '*') res.push(a * b);
			if(s == '/') res.push(a / b);
		
	
	return res.top();

decode-string

给定一个经过编码的字符串,返回它解码后的字符串
s = ‘3[a]2[bc]’ ’ -> ‘aaabcbc’
通过栈进行操作

string decodeString(string s)
	string res;
	int num = 0;
	stack<int> stackInt;
	stack<string> stackStr;
	
	for(char c : s)
		if(c == '[')
			stackInt.push(num);
			num = 0;
			stackStr.push(res);
			res = "";
		else if(c == ']')
			int times = stackInt.top(); // 重复次数
			stackInt.pop();
			for(int i = 0; i < times; i++)
				stackStr.top() += res;
			
			res = stackStr.top();
			stackStr.pop();
		else if(c >= '0' && c <= '9')
			num = num * 10 + c - '0';
		else
			res = res + c;
		
	

栈进行DFS递归搜索

栈进行递归搜索的模板

boolean DFS(int root, int target)
	Set<Node> visited;
	Stack<Node> s;
	add root to s;
	while(s is not empty)
		Node cur = the top element in s;
		return true if cur is target;
		for(Node next : the neighbors of cur)
			if(next is not in visited)
				add next to s;
				add next to visited;
			
		
		remove cur from s;
	
	return false;

binary-tree-inorder-traversal

二叉树中序遍历
使用栈保存已经访问过的节点,用于原路返回

vector<int> inorderTraversal(TreeNode* root)
	vector<int> res;
	if(root == NULL) return res;
	
	stack<TreeNode*> s;
	s.push(root);
	while(!s.empty())
		TreeNode *top = s.top();
		s.pop();
		if(top != NULL)
			// 中序遍历 左根右
			if(top->right) s.push(top->right);
			s.push(top);
			s.push(NULL); // 插入空节点标记访问过
			if(top->left) s.push(top->left);
		else
			res.push_back(s.top()->val);
			s.pop();
		
	
	return res;

clone-graph

给一个无向连通图一个节点的引用,返回改图的深拷贝

unordered_map<Node*, Node*> mp; // 标记访问过的节点
Node* cloneGraph(Node* node)
	if(node == NULL) return node;
	if(mp.count(node)) return mp[node]; //结束递归
	
	const auto newNode = new Node(node->val);
	mp[node] = newNode;
	for(auto n : node->neighbors)
		mp[node]->neighbors.push_back(cloneGraph(n));
	
	return mp[node];

number-of-islands

给定一个由’1’陆地和’0’水组成的二维网络,计算岛屿的数量。一个岛屿被水包围,并且它是通过水平或者垂直方向上与陆地连接而成,你可以假设网络的四个边均被水包围。
通过深度搜索遍历所有的可能性(标记已经访问过的节点)
这是经典的题目,面试中很常见

int numIslands(vector<vector<char>>& grid)
	int count = 0;
	for(int i = 0; i < grid.size(); i++)
		for(int j = 0; j < grid[0].size(); j++)
			if(grid[i][j] == '1')
				dfs(grid, i, j);
				count++;
			
		
	
	return count;

void dfs(vector<vector<char>>& grid, int i, int j)
	if(i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size())
		return ; //超出边界
	
	
	grid[i][j] = '2'; //标记访问过
	dfs(grid, i+1, j);
	dfs(grid, i-1, j);
	dfs(grid, i, j+1);
	dfs(grid, i, j-1);

largest-rectangle-in-histogram

给定n个非负整数,用来表示柱状图中各个柱子的高度,每个柱子彼此相邻,且宽度为1,求在该柱状图中,能勾勒出来的矩形的最大面积。
思路:求当前柱子为高度的最大面积,即转化为寻找小于当前值的左右两边值
用到了单调栈

int largestRectangleArea(vector<int>& heights)
	//基于各个高度的最大矩形是在出栈的时候计算,所以必须让所有高度都出栈
	//利用单调栈的性质,在原始数组后添加一个0
	heights.push_back(0);
	
	stack<int> s; //栈
	int maxArea = 0;
	for(int i = 0; i < heights.size(); i++)
		while(!s.empty() && heights[i] < heights[s.top])
			int h = heights[s.top()];
			s.pop();
			
			int w = s.empty() ? i : i - s.top() - 1;
			maxArea = max(maxArea, h*w);
		
		s.push(i);
	
	return maxArea;

队列

常用于BFS宽度搜索
常见题型:
implement-queue-using-stacks

使用两个栈实现队列

class MyQueue
public:
	stack<int> inStack;
	stack<int> outStack;
	
	MyQueue()
	
	
	
	void push(int x)
		inStack.push(x);
	
	
	int pop()
		cheak(); //将inStack栈内元素移动到outStack
		int top = outStack.top();
		outStack.pop();
		return top;
	
	
	int peek()
		//得到队首元素
		cheak();
		return outStack.top();
		
	
	
	bool empty()
		return inStack.empty() && outStack.empty();
	
	
	void cheak()
		if(outStack.empty())
			while(!inStack.empty())
				outStack.push(inStack.top());
				inStack.pop();
			
		
	
;

二叉树层次遍历模板

vector<vector<int>> levelOrder(TreeNode* root)
	vector<vector<int>> res;
	if(root == NULL) return res;
	
	queue<TreeNode*> q;
	q.push(root);
	while(!q.empty())
		int size = q.size();
		res.push_back(vector<int>());
		for(int i = 0; i < size; i++)
			TreeNode *top = q.front();
			res.back().push_back(top->val);
			q.pop();
			if(top->left) q.push(top->left);
			if(top->right) q.push(rop->right);
		
	
	return res;

01-matrix

给定一个由0和1组成的矩阵,找出每个元素到最近的0的距离,两个相邻元素间的距离是1
01矩阵问题,采用BFS方法求解
从0进入队列,弹出之后计算上下左右的结果,将上下左右重新进队列进行二层操作

vector<vector<int>> updateMatrix(vector<vector<int>>& matrix)
	int row = matrix.size(), col = matrix[0].size();
	vector<pair<int,int>> directions = 0, 1, 0, -1, 1, 0, -1, 0;
	vector<vector<int>> res(row, vector<int>(col, INT_MAX));
	queue<pair<int, int>> q;
	for(int i = 0; i < row; i++)
		for(int j = 0; j < col; j++)
			if(matrix[i][j] == 0)
				res[i][j] = 0;
				q.push(i, j);
			
		
	
	
	while(!q.empty())
		auto temp = q.front();
		q.pop();
		for(int i = 0; i < 4; i++)
			int x = temp.first + directions[i].first;
			int y = temp.second + directions[i].second;
			if(x >= 0 && x < row && y >= 0 && y <= col)
				// 保证在边界内
				if(res[x][y] > res[temp.first][temp.second] + 1)
					res[x][y] = res[temp.first][temp.second] + 1;
					q.push(x, y);
				
			
		
	
	return res;

总结

  • 知道栈的使用场景
    • 先入后出,保存临时值
    • 利用栈实现DFS
  • 熟悉队列的使用场景
    • 利用队列实现BFS

以上是关于算法模板-----栈和队列的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode算法题

栈和队列

011 模板栈和队列

算法:栈和队列

数据结构与算法学习笔记栈和队列

数据结构与算法学习笔记 栈和队列Ⅰ