栈和DFS

一、栈

1.理解 LIFO(后进先出) 和 栈的定义
在这里插入图片描述
栈是一个 LIFO (后进先出)数据结构。插入操作在栈中被称作入栈 push,总是在堆栈的末尾添加一个新元素;删除操作,退栈 pop ,将始终删除栈中的最后一个元素。

2.栈的实现

用动态数组实现栈

class MyStack {
    private:
        vector<int> data;               // store elements
    public:
        /** Insert an element into the stack. */
        void push(int x) {
            data.push_back(x);
        }
        /** Checks whether the queue is empty or not. */
        bool isEmpty() {
            return data.empty();
        }
        /** Get the top item from the queue. */
        int top() {
            return data.back();
        }
        /** Delete an element from the queue. Return true if the operation is successful. */
        bool pop() {
            if (isEmpty()) {
                return false;
            }
            data.pop_back();
            return true;
        }
};

用数组完整的实现:
顺序栈的实现

3.内置栈的使用

大多数流行的语言都提供了内置的栈库,我们需要知道常用的操作,如入栈和退栈。
stack s   //初始化
s.push(5)  //入栈
s.empty()  //栈空
s.pop()   //出栈,注意c++中出栈并不返回栈顶元素
s.top()   //获取栈顶
s.size()   //大小

4.常用方法

单调栈

单调栈,顾名思义,是栈内元素保持一定单调性(单调递增或单调递减)的栈。这里的单调递增或递减是指的从栈顶到栈底单调递增或递减。既然是栈,就满足后进先出的特点。

/* 单调递增栈 */
for(i = 0; i < n; i++){
	while(s.empty() && nums[i]>nums[s.top()]){
		s.pop();
		计算栈顶元素与该位置元素的关系结果;
		更新栈顶元素的结果; 
	} 
	s.push(i);  
}
输出结果; 

应用:
1.最基础的应用就是给定一组数,针对每个数,寻找它和它右边第一个比它大的数之间有多少个数。
2.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大。
3.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大。

技巧
逆序遍历
设置哨兵
栈存储数组下标

leetcode 739.每日温度
leetcode 901.股票价格跨度

leetcode 496.下一个更大元素 I
leetcode 581.最短无序连续子数组
leetcode 42.接雨水
leetcode 84.柱状图中最大的矩形
leetcode 85.最大矩形

[leetcode 402.移掉K位数字]
[leetcode 1081.不同字符的最小子序列]
[leetcode 316.去除重复字母]
[leetcode 321. 拼接最大数]

5.解决问题

leetcode 20.有效括号
leetcode 94.二叉树的中序遍历
leetcode 103.二叉树的锯齿形层次遍历
leetcode 144.二叉树的前序遍历
leetcode 145.二叉树的后序遍历
leetcode 150.逆波兰表达式求值
leetcode 155.最小栈
leetcode 225.用队列实现栈
leetcode 232.用栈实现队列
leetcode 341.扁平化嵌套列表迭代器
leetcode 394.字符串解码
leetcode 430.扁平化多级双向链表

二、DFS

在大多数情况下,我们在能使用 BFS 时也可以使用 DFS。但是有一个重要的区别:遍历顺序。与 BFS 不同,更早访问的结点可能不是更靠近根结点的结点。因此,你在 DFS 中找到的第一条路径可能不是最短路径。

有两种实现 DFS 的方法

1.递归

/* Return true if there is a path from cur to target. */
boolean DFS(Node cur, Node target, Set<Node> visited) {
    return true if cur is target;
    for (next : each neighbor of cur) {
        if (next is not in visited) {
            add next to visted;
            return true if DFS(next, target, visited) == true;
        }
    }
    return false;
}

当我们递归地实现 DFS 时,似乎不需要使用任何栈。但实际上,我们使用的是由系统提供的隐式栈,也称为调用栈(Call Stack)。
栈的大小正好是 DFS 的深度。因此,在最坏的情况下,维护系统栈需要 O(h),其中 h 是 DFS 的最大深度。在计算空间复杂度时,永远不要忘记考虑系统栈。
在上面的模板中,我们在找到第一条路径时停止。如果你想找到最短路径呢?可以再添加一个参数来指示你已经找到的最短路径。

2.栈

递归解决方案的优点是它更容易实现。 但是,存在一个很大的缺点:如果递归的深度太高,你将遭受堆栈溢出。 在这种情况下,您可能会希望使用 BFS,或使用显式栈实现 DFS。

/* Return true if there is a path from cur to target. */
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;
}

该逻辑与递归解决方案完全相同。 但我们使用 while 循环和栈来模拟递归期间的系统调用栈。

解决问题:

二维数组:
向四个方向搜索可以定义方向数组dirs
访问过的位置要在数组中修改标记位
leetcode 130.被围绕的区域
leetcode 200.岛屿数量
leetcode 542.01 矩阵
leetcode 733.图像渲染
leetcode 329.矩阵中的最长递增路径

leetcode 98.验证二叉搜索树
leetcode 101.对称二叉树
leetcode 104.二叉树的最大深度
leetcode 105.从前序与中序遍历序列构造二叉树
leetcode 108.将有序数组转换为二叉搜索树
leetcode 114.二叉树展开为链表
leetcode 116.填充每个节点的下一个右侧节点指针
leetcode 394.字符串解码
leetcode 124.二叉树中的最大路径和
leetcode 133.克隆图
leetcode 207.课程表
leetcode 210.课程表 II
leetcode 301.删除无效的括号
leetcode 337.打家劫舍 III
leetcode 494.目标和
leetcode 841.钥匙和房间

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值