算法题解记录9+++有效的括号(百日筑基)

题目描述:

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

        本题1、2的描述,结合后,我的理解是:左括号右括号必须成对出现,且不允许嵌套。比如:"()[]{}[]"表示正确、但"([)] "表示错误,因为(括号和)括号没连在一起。

        该题在提交时,有一个用例"([)]"答案为错误,故我在此提示。

有效字符串需满足:

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

解题准备:

        1.了解栈:栈是一种线性的数据结构,可以理解为一个特殊数组(或链表),仅提供两个基础操作:入栈和出栈,并且具有先进后出的性质【可以看成只有一个口,同时作为出口、入口的结构】(类似于配对、转变字符串顺序、状态模式undo等,都可以用栈来做)【在此作为了解,我会在后面展示为什么要用栈,其实可以用其它结构

        2.了解本题涉及的基础操作:既然要判断s是否为有效字符串,应该要遍历s,所以涉及查找;涉及栈,故涉及入栈、出栈,有增加和删除。。故此,有增删查

        3.模拟本题操作:本题操作好像有点无从下手,如果是人眼看,一下子就明白了。但是机器是分步骤的,所以有点奇怪,在此先不说。

解题难点分析:

        本题难点,在于如何把一眼看出来的模糊,转换为一步步迭代的清晰

        思考步骤:

        1.假设字符串为")([]",人怎么做?

                显然,开头就遇到),所以直接返回false。

        2.进阶一点,如果是"()[])(",人怎么做?

                显然,虽然前面四个字符都匹配,但是)(也犯了1的错误,返回false。

        3.好像有点意思了,能不能分步来做?

                我们知道,一个字符串,本质就是一个字符数组,能不能从数组的角度来理解?

        4.对于字符数组,怎么理解?

                1st.我们发现,对于)([],从下标0开始,)前面不满足匹配,故返回false。

                2nd.对于(),从下标0开始, (无法判断返回true或false,移至下标1,)应该找个匹配了,发现下标0恰好满足。又因为字符数组刚好遍历结束,所以应该返回true。

                3rd.可是,如果字符串为())呢?虽然知道下标0、1满足,但是移动到下标2的字符')'时,找前面的字符,明显有下标0为'(',满足题意,返回true?明显错误。

                4th.由3rd,我们应该建立一个机制,如果被遍历过的左括号,就不能再遍历,干脆用个boolean数组,不过最初,我们无法确定左括号数目,难道要用可变的数组?反正右括号如果遍历到了,也不再使用,干脆直接用个长度为s.length()的boolean数组,标志左、右括号的使用情况。

                5th.那么,再面对()),此时由于下标0、1已经标志为true(或false),下标2的),明显不满足题意,返回false;

                6th,对于"(){}()"、"()[)"同理了

如何转变为用栈解决:

        我们明显可以看出,对于字符数组,遍历时,如果是左括号,不处理,右括号,则处理两个数据。

        我们遍历字符数组(命名为charA),使用了boolean数组(命名为boolean)辅助,看起来还可以,深入思考一下,比如字符串"([{}])"。

        1.明显,在遍历0、1、2时,对于下标0、1、2,无法使其为true。

        2.面对下标3,由于我们没保存数组情况(实际保存了也得遍历),所以得先遍历一次boolean,查找下标x<3的数据,是否存在false(未被使用)的数据,并且,如果未被使用,是否为{,===其实也可以发现,本题还存在可能出错。【所以,解决方法就是倒着查,从下标3-1=2的数据,一直查到=0的数据,第一个false的boolean,是否为{,是则OK,不是则返回false】

        3.假设步骤2完美,到了下标为4的字符,又要从3开始遍历(使用【】中的方法),一直到下标为1,才找到。

        4.同理。

        所以,明显可以看到,boolean数组在解决问题的同时,存在大量重复运算。

        既然已经被使用过的数据,为什么一而再再而三的遍历呢?

        如果我们有一个数组A,其长度随时随着存储的数据量的变化而变化,比如此时A中有3个元素,其长度就为3,此时A有5个元素,长度就为5。

        那多好?遇到左括号,把它添加到A中,遇到右括号,把对应的左括号从A中删除。

        这时候,我们只需要判断两件事,1.遍历结束后,A中是否残留元素。

        2.当遇到右括号时,A是否有数据?如果有,是否匹配?【右括号来临,可以直接查看A.length -1,如果不匹配,返回false即可】

        由此,我们发现,普通的数组很难处理,但栈确实很满足这些要求,所以用栈。【栈的长度不可变,但是其元素长度却被标记,可以认为可变,遇到左括号入栈,右括号pop一个栈的元素进行比较,只有两种结果,要不不匹配返回false,要不匹配遍历charA的下一个元素】

代码:

        时间复杂度大约是O(n) ,n为字符串长度

class Solution {
    public boolean isValid(String s) {
        Stack<Character> data=new Stack<>();
        for(char temp:s.toCharArray()){
            if(temp=='('||temp=='['||temp=='{'){
                data.push(temp);
            }else{
                if(data.isEmpty()){
                    return false;
                }
                if(!fuzhu(data, temp)){
                    return false;
                }
            }
        }

        if(!data.isEmpty()){
            return false;
        }

        return true;
    }

    private boolean fuzhu(Stack<Character> data, char k){
        char var;

        if(k==')'){
            var=data.pop();
            if(var=='('){
                return true;
            }
            return false;
        }else if(k=='}'){
            var=data.pop();
            if(var=='{'){
                return true;
            }
            return false;
        }else{
            var=data.pop();
            if(var=='['){
                return true;
            }
            return false;
        }
    }
}

以上内容即我想分享的关于力扣热题9的一些知识。

        我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值