栈的经典算法问题(算法村第四关白银挑战)

news2024/10/7 14:25:27

括号匹配问题

有效的括号

20. 有效的括号 - 力扣(LeetCode)

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成
利用HashMap
public boolean isValid(String s)
    {
        HashMap<Character, Character> hashMap = new HashMap<>();

        //key为左括号,value为右括号
        hashMap.put('(',')');
        hashMap.put('[',']');
        hashMap.put('{','}');

        ArrayDeque<Character> stack = new ArrayDeque<>();

        for (int i = 0; i < s.length(); i++)
        {
            char c = s.charAt(i);

            if(hashMap.containsKey(c))  //c是左括号
                stack.push(c);  //左括号入栈
            else    //c是右括号
            {
                //栈空,或者该右括号与栈顶的左括号不匹配
                if (stack.isEmpty() || c != hashMap.get(stack.peek()))
                    return false;
                else //匹配
                    stack.pop();    //栈顶的左括号出栈
            }
        }

        //循环结束后,若栈空则s是括号有效的字符串,否则说明还有左括号没匹配
        return stack.isEmpty();
    }
非HashMap版
public boolean isLeftBracket(char c)
    {
        return c == '(' || c == '{' || c == '[';
    }

    public char partner(char c)
    {
        switch(c)
        {
            case ')': return '(';
            case '}': return '{';
            case ']': return '[';
            default: return ' ';
        }
    }

    public boolean isValid(String s) 
    {
        //括号总数必须是偶数
        if(s.length() % 2 != 0)
            return false;

        Stack<Character> stack = new Stack<>();

        for(int i = 0; i < s.length(); i++)
        {
            char c = s.charAt(i);

            if(isLeftBracket(c))    //c是左括号
                stack.push(c);
            else    //c是右括号
            {   
                //栈空,或者该右括号与栈顶的左括号不匹配
                if(stack.isEmpty() || stack.peek() != partner(c))
                    return false;
                else    //匹配
                    stack.pop();  //栈顶的左括号出栈
            }
        }

        return stack.isEmpty(); //栈空则s是括号有效的字符串,栈不空说明还有左括号没匹配
    }

括号生成

22. 括号生成 - 力扣(LeetCode)

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1
输出:["()"]

提示:

  • 1 <= n <= 8
深搜,做减法

在这里插入图片描述

public List<String> generateParenthesis(int n)
{
    //特判
    if (n == 0)
        return null;

    //结果集
    ArrayList<String> res = new ArrayList<String>();

    //深搜,找出全部有效括号组合
    DFS(res, n, n, "");

    return res;
}

/**
 * @param res 结果集
 * @param left 左括号还能用几个
 * @param right 右括号还能用几个
 * @param curStr 当前递归所得到的字符串
 */
public static void DFS(List<String> res, int left, int right, String curStr)
{
    //递归终止;将一种组合添加到结果集
    if (left == 0 && right == 0)
    {
        res.add(curStr);
        return;
    }

    //尝试使用右括号后,若左括号剩余数量大于右括号剩余数量,则“剪枝”(否则会违背有效括号的定义)
    if (left > right)
        return;

    //优先使用左括号
    if (left > 0)
        DFS(res, left - 1, right, curStr + "(" );

    //使用右括号
    if (right > 0)
        DFS(res, left, right - 1, curStr +")" );
}
深搜,做加法

在这里插入图片描述

public List<String> generateParenthesis(int n)
{
    //特判
    if (n == 0)
        return null;

    //结果集
    ArrayList<String> res = new ArrayList<String>();

    //深搜,寻找全部有效括号组合
    DFS(res, 0, 0, "", n);

    return res;
}

/**
 * @param res 结果集
 * @param left 左括号使用了几个
 * @param right 右括号使用使用了几个
 * @param curStr 当前递归所得到的字符串
 * @param n 题目所给的括号生成对数
 */
public static void DFS(List<String> res, int left, int right, String curStr, int n)
{
    //递归终止;将一种组合添加到结果集
    if (left == n && right == n)
    {
        res.add(curStr);
        return;
    }

    //尝试使用右括号后,若左括号使用数量小于右括号使用数量,则“剪枝”(否则会违背有效括号的定义)
    if (left < right)
        return;

    //优先使用左括号
    if (left < n)
        DFS(res, left + 1, right, curStr + "(", n);

    //使用右括号
    if (right < n)
        DFS(res, left, right + 1, curStr +")", n);
}
广搜
/**
 * 队列结点
 */
class Node
{
    String curStr;
    int left;   //左括号还剩几个没用
    int right; //右括号还剩几个没用

    public Node(String curStr, int left, int right)
    {
        this.curStr = curStr;
        this.left = left;
        this.right = right;
    }
}

public List<String> generateParenthesis_3(int n)
{
    //特判,否则n==0时下面的算法会返回""
    if(n == 0)
        return null;

    //结果集
    ArrayList<String> res = new ArrayList<String>();

    ArrayDeque<Node> queue = new ArrayDeque<>();
    //初始结点入队
    queue.offer(new Node("", n, n));

    while (!queue.isEmpty())
    {
        //队头元素出队
        Node curNode = queue.poll();

        //生成了一组有效括号
        if(curNode.left == 0 && curNode.right == 0)
            res.add(curNode.curStr);

        //优先使用左括号
        if (curNode.left > 0)
            queue.offer(new Node(curNode.curStr + "(", curNode.left - 1, curNode.right));

        //左括号少于右括号的情况下,才能使用右括号
        if (curNode.right > 0 && curNode.left < curNode.right)
            queue.offer(new Node(curNode.curStr + ")", curNode.left, curNode.right - 1));
    }

    return res;
}

最小栈

155. 最小栈 - 力扣(LeetCode)

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

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

提示:

  • -231 <= val <= 231 - 1
  • poptopgetMin 操作总是在 非空栈 上调用
  • push, pop, top, and getMin最多被调用 3 * 104

建立一个存储val的元素栈和一个辅助栈,辅助栈与元素栈同步push和pop,并存储每个val入栈后对应的最小值

以空间换时间

ArrayDeque<Integer> stack;  //元素栈

ArrayDeque<Integer> minStack;   //辅助栈

public MinStack()
{
    stack = new ArrayDeque<>();
    minStack = new ArrayDeque<>();
    minStack.push(Integer.MAX_VALUE);
}

public void push(int val)
{
    stack.push(val);
    minStack.push(Math.min(minStack.peek(), val));
}

public void pop()
{
    stack.pop();
    minStack.pop();
}

public int top()
{
    return stack.peek();
}

public int getMin()
{
    return minStack.peek();
}

最大栈

716. 最大栈 - 力扣(LeetCode)

题目要求与【最小栈】基本相同,难度提升在于要我们实现**“popMax():检索并返回栈中最大元素,并将其移除。如果有多个最大元素,只要移除最靠近栈顶的那个。”**,以及数据增强,对时间效率要求更高

元素栈+辅助栈

对时间要求不严格的情况下,可以沿用最小栈的解法,并建立一个临时栈实现popMax()

public class MaxStack
{
    ArrayDeque<Integer> stack;  //元素栈
    ArrayDeque<Integer> maxStack;   //辅助栈

    public MaxStack()
    {
        stack = new ArrayDeque<>();
        maxStack = new ArrayDeque<>();
        maxStack.push(Integer.MIN_VALUE);
    }

    public void push(int x)
    {
        stack.push(x);
        maxStack.push(Math.max(maxStack.peek(), x));
    }

    public int pop()
    {
        maxStack.pop();
        return stack.pop();
    }

    public int top()
    {
        return stack.peek();
    }

    public int peekMax()
    {
        return maxStack.peek();
    }

    public int popMax()
    {
        int max = peekMax();

        ArrayDeque<Integer> tempStack = new ArrayDeque<>();

        //将元素栈stack中在最大元素之上的所有元素一次倾倒、存储起来。辅助栈需要同步操作
        while (top() != max )
            tempStack.push(pop());

        //找到距离栈顶最近的最大元素,删除它
        pop();

        //将临时栈中的元素倒回去
        while (!tempStack.isEmpty())
            push(tempStack.pop());

        return max;
    }
}
用链表结点同时存储val和max

逻辑与第一种解法一致,但一样无法通过最后一个严格的测试用例

class Node
{
    int val;    //元素的值
    int max;    //此时的最大值
    Node next;

    public Node(int val, int max, Node next) {
        this.val = val;
        this.max = max;
        this.next = next;
    }
}

class MaxStack_2
{
    Node head = null;  //指向表首元素
    public MaxStack_2(){}

    public void push(int x)
    {
        if (head == null)
            head = new Node(x, x, null);
        else    //x与之前的最大值比较,得出新的最大值
            head = new Node(x, Math.max(head.max, x), head);
    }

    public int pop()
    {
        int val = head.val;
        head = head.next;

        return val;
    }

    public int top()
    {
        return head.val;
    }

    public int peekMax()
    {
        return head.max;
    }

    public int popMax()
    {
        int Max = head.max;
        Node tempList = null;   //临时链表的头指针,作用与临时栈的栈顶指针相同

        while (head.val != Max)
        {
            Node suc = head.next;
            head.next = tempList;
            tempList = head;
            head = suc;
        }

        //删除最大元素
        head = head.next;

        //“倒回去”
        while (tempList != null)
        {
            push(tempList.val);
            tempList = tempList.next;
        }

        return Max;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1351890.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

包围盒体积-体积计算

文章目录 环境&#xff1a;1.1 包围盒法介绍&#xff1a;2.1 python代码3.1 可视化4.1 体积Calculation 环境&#xff1a; Open3D 1.1 包围盒法介绍&#xff1a; 求解离散点最优包围空间 常用的凸包算法&#xff1a; AABB OOB 2.1 python代码 conda activete deeplabv3plus(…

一起读《奔跑吧Linux内核(第2版)卷1:基础架构》- 大小端字节序

关注 点赞 不错过精彩内容 大家好&#xff0c;我是硬核王同学&#xff0c;最近在做免费的嵌入式知识分享&#xff0c;帮助对嵌入式感兴趣的同学学习嵌入式、做项目、找工作! Hello&#xff0c;大家好我是硬核王同学&#xff0c;是一名刚刚工作一年多的Linux工程师&#xff0…

【hyperledger-fabric】将智能合约部署到通道

简介 本文主要来自于B站视频教学视频&#xff0c;也主要参看了官方文档中下图这一章节。针对自己开发的代码做出相应的总结。 1.启动网络 # 跳转到指定的目录 cd /root/fabric/fabric-samples/test-network# 启动docker容器并且创建通道 ./network.sh up createChannel2.打…

CMake支持的编译平台和IDE

文章目录 简介支持的IDEVisual Studio支持示例 其他编译器和生成器支持MinGW示例 IDE集成Eclipse示例 实验性和特殊平台支持总结 简介 CMake是一个非常强大的跨平台自动化构建工具&#xff0c;它支持生成多种类型的项目文件&#xff0c;覆盖了广泛的开发环境和编译器。在这篇博…

wordpress在界面将站点地址直接修改为https导致上不去问题的解决办法

wordpress在界面将站点地址直接修改为https导致上不去问题的解决办法 #修改数据库yz_options

【Matlab】基于遗传算法优化BP神经网络 (GA-BP)的数据时序预测(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88682033 一&#xff0c;概述 基于遗传算法优化BP神经网络 (GA-BP) 的数据时序预测是一种常用的机器学习方法&#xff0c;用于预测时间序列数据的趋势和未来值。 在使用这种方法之前&#xff0c;需要将时间序…

Nacos设置账号密码

1、控制台设置 # 开启账号密码验证 nacos.core.auth.enabledtrue# 设置账号密码 nacos.core.auth.usernamenacos nacos.core.auth.passwordnacos1232、数据库设置 密码为&#xff1a;nacos&#xff0c;对应加密信息是&#xff1a; $2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2k…

哨兵1号回波数据(L0级)FDBAQ压缩算法详解

本专栏目录: 全球SAR卫星大盘点与回波数据处理专栏目录-CSDN博客 1. 全球SAR卫星回波数据压缩算法统计 各国的SAR卫星的压缩算法按照时间轴排列如下: 可以看出传统的分块BAQ压缩算法(上图粉色)仍然是主流,哨兵1号其实也有传统的BAQ压缩模式。 本文介绍哨兵1号用的FDBAQ算…

图像分割-漫水填充法 floodFill (C#)

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 本文的VB版本请访问&#xff1a;图像分割-漫水填充法 floodFill-CSDN博客 FloodFill方法是一种图像处理算法&#xff0c;它的目的是…

优维科技2024战略定位:新一代运维核心系统提供商

01 经济复苏「走远路」 过去几年&#xff0c;全球经济持续低迷&#xff0c;2024会迎来转机吗&#xff1f; 回顾2023年&#xff0c;尽管经济复苏动能式微&#xff0c;但全球经济因有效控制通胀而展现出来的韧性&#xff0c;让包括中国在内的大部分经济体躲过了深度衰退的陷阱&…

(NeRF学习)NeRFStudio安装win11

参考&#xff1a; 【深度学习】【三维重建】windows11环境配置tiny-cuda-nn详细教程nerfstudio介绍及在windows上的配置、使用NeRFStudio官网githubRuntimeError: PytorchStreamReader failed reading zip archive: failed finding central directory原因及解决 目录 requireme…

二叉树的层序遍历,力扣

目录 题目地址&#xff1a; 题目&#xff1a; 我们直接看题解吧&#xff1a; 解题方法&#xff1a; 方法分析&#xff1a; 解题分析&#xff1a; 解题思路&#xff1a; 代码实现&#xff1a; 代码补充说明&#xff1a; 题目地址&#xff1a; 102. 二叉树的层序遍历 - 力扣&…

使用华为云鲲鹏弹性云服务器部署Discuz

本实验将在华为云鲲鹏弹性云服务器CentOS系统的实例上&#xff0c;部署Discuz!项目&#xff0c;并进行初步的安装测试。 注意&#xff1a;官网文档有些链接失效&#xff0c;本文在官方文档的基础上作出修改&#xff0c;具体参见Discuz安装这一步 操作前提&#xff1a;登录华为…

Unity中Shader的Reversed-Z(DirectX平台)

文章目录 前言一、在对裁剪坐标归一化设置NDC时&#xff0c;DirectX平台Z的特殊二、在图形计算器中&#xff0c;看一下Z值反转前后变化1、在图形计算器创建两个变量 n 和 f 分别 控制近裁剪面 和 远裁剪面2、带入公式得到齐次裁剪空间下Z值3、进行透视除法4、用 1 - Z 得出Z值反…

邮件群发称呼怎么写?写群发邮件开头技巧?

如何写外贸邮件群发称呼&#xff1f;外贸群发邮件开头怎么称呼&#xff1f; 邮件群发已成为企业、个人和组织之间沟通的重要手段。而一个恰当的称呼&#xff0c;不仅能够展现出礼貌和尊重&#xff0c;还能够拉近彼此的距离。那么&#xff0c;如何写好邮件群发的称呼呢&#xf…

Java 读取超大excel文件

注意&#xff1a;此参考解决方案只是针对xlsx格式的excel文件&#xff01; Maven <dependency><groupId>com.monitorjbl</groupId><artifactId>xlsx-streamer</artifactId><version>2.2.0</version> </dependency>读取方式1…

杰发科技AutoGen自动生成7801代码——PWM

1.AutoGen生成代码非常简单&#xff0c;1s输出PWM波 只需修改如下频率和占空比即可 注意Pin脚对应的通道号是否正确 2.生成的代码可以直接编译烧录 3.结果

无边界支付:数字货币如何改变跨境电商?

在全球数字化的浪潮中&#xff0c;数字货币的崛起成为跨境电商领域的一场革命。本文将深入探讨数字货币如何重新定义支付体系&#xff0c;对跨境电商带来的影响以及未来可能的发展方向。 数字货币的崛起 随着比特币等数字货币的逐渐走俏&#xff0c;传统支付体系的边界逐渐被打…

微信服务号升级订阅号条件

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;首先我们要看一下服务号和订阅号的主要区别。1、服务号推送的消息没有折叠&#xff0c;消息出现在聊天列表中&#xff0c;会像收到消息一样有提醒。而订阅号推送的消息是折叠的&#xff0c;“订阅号…

【linux kernel】linux的SPI框架分析

文章目录 一、linux内核中的SPI框架二、SPI核心的初始化三、SPI核心的数据结构1、struct spi_statistics2、struct spi_delay3、struct spi_device4、struct spi_driver5、struct spi_controller6、struct spi_res7、struct spi_transfer8、struct spi_message9、struct spi_bo…