栈题目:使括号有效的最少添加

题目

标题和出处

标题:使括号有效的最少添加

出处:921. 使括号有效的最少添加

难度

4 级

题目描述

要求

一个括号字符串是有效的,当且仅当满足下列条件之一:

  • 字符串是一个空字符串;
  • 字符串可以写为 AB \texttt{AB} AB A \texttt{A} A B \texttt{B} B 字符串连接),其中 A \texttt{A} A B \texttt{B} B 都是有效括号字符串;
  • 字符串可以写为 (A) \texttt{(A)} (A),其中 A \texttt{A} A 是一个有效括号字符串。

给定一个括号字符串 s \texttt{s} s。每一步添加可以在字符串的任意位置插入一个括号。

  • 例如, s   =   "()))" \texttt{s = "()))"} s = "()))",可以插入一个左括号得到 "(()))" \texttt{"(()))"} "(()))" 或者插入一个右括号得到 "())))" \texttt{"())))"} "())))"

返回使 s \texttt{s} s 有效的最少添加次数。

示例

示例 1:

输入: s   =   "())" \texttt{s = "())"} s = "())"
输出: 1 \texttt{1} 1

示例 2:

输入: s   =   "(((" \texttt{s = "((("} s = "((("
输出: 3 \texttt{3} 3

示例 3:

输入: "()" \texttt{"()"} "()"
输出: 0 \texttt{0} 0

示例 4:

输入: "()))((" \texttt{"()))(("} "()))(("
输出: 4 \texttt{4} 4

数据范围

  • 1 ≤ s.length ≤ 1000 \texttt{1} \le \texttt{s.length} \le \texttt{1000} 1s.length1000
  • s[i] \texttt{s[i]} s[i] ‘(’ \texttt{`('} ‘(’ ‘)’ \texttt{`)'} ‘)’

解法一

思路和算法

有效的括号字符串中,左括号和右括号成对出现,在每对左右括号中,左括号在右括号的左边。

如果一个左括号右边没有右括号匹配,或者一个右括号左边没有左括号匹配,则需要插入相应的括号,才能使括号字符串有效。

可以使用栈存储左括号,从左到右遍历字符串 s s s,计算使字符串 s s s 有效的最少添加次数。对于每个字符,进行如下操作:

  • 遇到左括号,则将左括号入栈;

  • 遇到右括号且栈不为空,则将栈顶的左括号出栈,表示当前的右括号和栈顶的左括号匹配;

  • 遇到右括号且栈为空,则当前的右括号没有左括号匹配,因此需要插入一个左括号,将添加次数加 1 1 1

遍历结束之后,如果栈不为空,则栈内的每个左括号都没有右括号匹配,对于栈内的每个左括号都需要插入一个右括号,因此将添加次数加上栈内左括号个数。

最终得到的添加次数即为使字符串 s s s 有效的最少添加次数。

注意上述操作中,只计算需要插入的左括号个数和右括号个数,没有考虑插入括号的位置,这是因为每一步添加可以在字符串的任意位置插入一个括号,对于每个右括号,总能在其左边找到一个位置插入左括号,对于每个左括号,总能在其右边找到一个位置插入右括号。

代码

class Solution {
    public int minAddToMakeValid(String s) {
        int add = 0;
        Deque<Character> stack = new ArrayDeque<Character>();
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            if (c == '(') {
                stack.push(c);
            } else {
                if (!stack.isEmpty()) {
                    stack.pop();
                } else {
                    add++;
                }
            }
        }
        add += stack.size();
        return add;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要遍历字符串 s s s 一次,每次入栈和出栈操作的时间都是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。空间复杂度主要取决于栈空间,栈内的元素个数为 O ( n ) O(n) O(n)

解法二

思路和算法

也可以不用栈,而是使用计数的方式计算使字符串 s s s 有效的最少添加次数。

使用 add \textit{add} add 记录添加次数,使用 count \textit{count} count 记录未匹配的左括号的数量,初始时 add = count = 0 \textit{add} = \textit{count} = 0 add=count=0

从左到右遍历字符串 s s s,对于每个字符,进行如下操作:

  • 遇到左括号,则将 count \textit{count} count 1 1 1

  • 遇到右括号且 count > 0 \textit{count} > 0 count>0,则将 count \textit{count} count 1 1 1

  • 遇到右括号且 count = 0 \textit{count} = 0 count=0,则当前的右括号没有左括号匹配,因此需要插入一个左括号,将 add \textit{add} add 1 1 1

遍历结束之后, count \textit{count} count 为尚未匹配的左括号的数量,对于每个尚未匹配的左括号都需要插入一个右括号,因此将 add \textit{add} add count \textit{count} count

最终得到的 add \textit{add} add 即为使字符串 s s s 有效的最少添加次数。

代码

class Solution {
    public int minAddToMakeValid(String s) {
        int add = 0;
        int count = 0;
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            if (c == '(') {
                count++;
            } else {
                if (count > 0) {
                    count--;
                } else {
                    add++;
                }
            }
        }
        add += count;
        return add;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要遍历字符串 s s s 一次,每次更新计数的时间都是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( 1 ) O(1) O(1)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值