LeetBook乐扣题库 20. 有效的括号

一 题目描述

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

有效字符串需满足:

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

示例 1:

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

示例 2:

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

示例 3:

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

二 方法代码

思路讲解:

括号都是成对出现的,并且它的特性是,如果两对括号是包含关系,那么一定是嵌套的,类似于洋葱,即内层括号对应一组,外层对应一组,例如“( [ { } ] )”或者( [ ] { }),不会乱套,不会出现内层括号是” { ] “这样不对应的组合。

因此,当我们取出一个右括号时,要去看它前一个的左括号是不是对应的,如果是,就消掉,如果不是就错误;如果是左括号,我们就存储起来,等着遇到下一个右括号。这个就对应哈希表Key-Value的映射关系,因此我们需要使用哈希表

依照这个思路,我们可以联想到堆栈只能从一端进行元素的添加和删除的操作受限的线性表为栈,它具有后进先出(LIFO,Last In First Out)的特性。因此我先遇到的左括号压在栈底,后遇到的左括号放在栈顶,当遇到右括号,需要取出上一个最近的左括号时,拿出栈顶就好。

不过现在Java都使用Deque(双端队列)来替代堆栈,因为Deque既可以当队列也可以当堆栈,这是Deque的一些使用方法的等效对应方法,来源自Java数据结构之Deque(双端队列)_java deque-CSDN博客

  • 方法一

public boolean isValid1(String s) {
        if(s.length() % 2 == 1){
            //因为括号成对出现,所以长度一定是偶数
            return false;
        }

        Map<Character, Character> map = new HashMap<Character, Character>(){
            {
                //哈希表,注意key是右括号,因为要遇到右括号后要去双向队列中消除左括号
                put(')', '(');
                put(']', '[');
                put('}', '{');
            }
        };

        //创建双向队列,即又可以当堆栈也可以当队列,可以在两端进行插入和删除
        Deque<Character> stack = new LinkedList<Character>();

        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if(map.containsKey(c)){//当取到的是右边括号的时候
                //如果队列为空,所以没有对应的左括号,一定是错的
                //如果从前端取出的元素不是相对应的左括号,也一定是错的
                if(stack.isEmpty() || stack.peekFirst() != map.get(c)){
                    return false;
                }
                //如果没有返回false,说明队列中找到了对应的左括号,就删除掉前端的第一个元素
                //pop()等效于Deque的removeFirst()方法
                stack.pop();
            }else{//当取到的是左括号时,就插入到前端中
                //因为括号都是对应出现的,取到的第一个右括号应该对应最后出现的左括号
                //eg: ([]),第一个取到的右括号 ']' 对应最后出现的左括号 '['
                //因此,左括号要插入到前端而不是后端,这样peekFirst拿到的就是后出现的左括号
                stack.addFirst(c);
            }
        }

        //如果最后队列为空,说明都可以两两对应抵消掉
        return stack.isEmpty();
    }
  • 方法二

这个是我在力扣评论区找到的,运行速度要快:本链接导向大佬的力扣评论区

因为HashMap创建的键值对需要时间,所以会耽误运行速度。其本质就是一个对应关系,因此大佬直接修改思路,让当取出左括号时,就直接插入对应的右括号到栈中,这样就省去了HashMap的运行时间

为什么不像上一个方法一样key为右括号,然后遇到右括号压左括号入栈,而是取出左括号后将右括号压入栈中,是因为思路相反,上一个是遇到右括号后取出栈顶的左括号看是否对应,这个思路是遇到左括号后,直接将对应的右括号压入栈,这样当遇到第一个右括号时,就取出栈顶的理论上正确的右括号取出,做对比看是否一致,一致说明没问题,看下一个括号,不一致就返回错误

缺点是不易于维护和修改,把字符配对处理放一起的话,后续扩展会比较好,比如再加<>配对,大佬的这个修改会有些麻烦,也容易出错,代码设计其中一个原则:对扩展开放,对修改关闭。

public boolean isValid2(String s) {
        if(s.length() % 2 == 1){
            //因为括号成对出现,所以长度一定是偶数
            return false;
        }

        Stack<Character>stack = new Stack<Character>();
        //把字符串转为字符数组,然后逐个遍历,
        for(char c: s.toCharArray()){
            if(c=='('){
                //将左括号对应的右括号压入栈,下面else if的同理
                stack.push(')');
            }
            else if(c=='['){
                stack.push(']');
            }
            else if(c=='{'){
                stack.push('}');
            }
            //剩下的情况是取出右括号了,那就拿出栈顶的正确的右括号做对比看是否一致
            else if(stack.isEmpty()||c!=stack.pop()){
                return false;
            }
        }
        return stack.isEmpty();
    }

三 运行结果

方法一:

方法二:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值