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

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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值