20.有效的括号

  1. 20.有效的括号
    1. 20.1 题目
    2. 20.2 题解
      1. 列表装左括号对比
      2. 双栈弹出括号验证
      3. 单栈弹出括号验证
      4. 使用字典和栈验证括号
    3. 20.3 代码
    4. 20.4 运行结果

20.有效的括号


20.1 题目

给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:

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

示例:

  • 示例 1:

    • 输入:s = "()"
    • 输出:true
  • 示例 2:

    • 输入:s = "()[]{}"
    • 输出:true
  • 示例 3:

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

提示:

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

20.2 题解

列表装左括号对比

// 方法一:列表装左括号对比
// 遍历字符串,是左括号就丢到列表里,是右括号的话就判断和列表尾部括号是否匹配
static bool IsValid1(string s)
{
    // 检查字符串长度是否为偶数,奇数长度的字符串无法满足括号闭合条件
    if (s.Length % 2 != 0) return false;

    // 用于存储左括号的列表
    List<char> leftBracketList = new List<char>();

    // 遍历输入字符串的每个字符
    for (int i = 0; i < s.Length; i++)
    {
        // 调用 ReturnLeftBracket 函数获取与当前右括号相匹配的左括号
        char leftBracket = ReturnLeftBracket(s[i]);

        // 如果返回的左括号不为空格,说明当前字符是右括号
        if (leftBracket != ' ')
        {
            // 检查 leftBracketList 中是否有左括号与当前右括号匹配
            if (leftBracketList.Count > 0 && leftBracketList[leftBracketList.Count - 1] == leftBracket)
            {
                // 如果匹配成功,移除 leftBracketList 中的匹配左括号
                leftBracketList.RemoveAt(leftBracketList.Count - 1);
            }
            else
            {
                // 如果匹配失败,说明括号闭合顺序不正确,返回 false
                return false;
            }
        }
        else
        {
            // 如果返回的左括号为空格,说明当前字符是左括号,将其添加到 leftBracketList 中
            leftBracketList.Add(s[i]);
        }
    }

    // 最终检查 leftBracketList 是否为空,若为空,则括号闭合成功,返回 true;否则,返回 false
    return leftBracketList.Count == 0;
}

// 根据右括号返回相应的左括号
static char ReturnLeftBracket(char rightBracket)
{
    switch (rightBracket)
    {
        case ')':
            return '(';
        case '}':
            return '{';
        case ']':
            return '[';
        default:
            return ' '; // 如果输入的不是右括号,则返回空格表示不匹配
    }
}

双栈弹出括号验证

// 方法二:双栈弹出括号验证
// 先把所有字符丢到一个字符栈中,循环弹出字符串判断是否是右括号,是右括号丢到右括号栈,是左括号弹出右括号栈顶元素看是否匹配
static bool IsValid2(string s)
{
    // 检查字符串长度是否为偶数,奇数长度的字符串无法满足括号闭合条件
    if (s.Length % 2 != 0) return false;

    // 用于存储字符的栈,按顺序将字符串的字符入栈
    Stack<char> bracketPushStack = new Stack<char>();

    // 将字符串的字符按顺序入栈
    for (int i = 0; i < s.Length; i++)
    {
        bracketPushStack.Push(s[i]);
    }

    // 用于存储右括号的栈
    Stack<char> rightBracketPopStack = new Stack<char>();

    // 遍历字符栈中的每个字符
    while (bracketPushStack.Count > 0)
    {
        // 弹出栈顶字符
        char nowBracket = bracketPushStack.Pop();

        // 如果是右括号,将其入右括号栈
        if (nowBracket == ')' || nowBracket == '}' || nowBracket == ']')
        {
            rightBracketPopStack.Push(nowBracket);
        }
        // 如果是左括号,进行匹配操作
        else if (nowBracket == '(' || nowBracket == '{' || nowBracket == '[')
        {
            // 如果右括号栈为空,说明没有匹配的右括号,返回 false
            if (rightBracketPopStack.Count == 0)
            {
                return false;
            }

            // 调用 IsLeftBracketMatching 函数判断左右括号是否匹配
            bool isBracketMatching = IsLeftBracketMatching(nowBracket, rightBracketPopStack.Pop());

            // 如果不匹配,返回 false
            if (!isBracketMatching)
            {
                return false;
            }
        }
        else
        {
            // 如果字符既不是左括号也不是右括号,返回 false
            return false;
        }
    }

    // 最终检查右括号栈是否为空,若为空,则括号闭合成功,返回 true;否则,返回 false
    return rightBracketPopStack.Count == 0;
}

// 判断左右括号是否匹配
static bool IsLeftBracketMatching(char leftBracket, char rightBracket)
{
    switch (leftBracket)
    {
        case '(':
            return rightBracket == ')';
        case '{':
            return rightBracket == '}';
        case '[':
            return rightBracket == ']';
        default:
            return false; // 如果输入的不是左括号,则返回 false
    }
}

单栈弹出括号验证

// 方法三:单栈弹出括号验证
// 遍历字符串,如果是左括号把对应的右括号丢进栈,是右括号就弹出栈判断是否相等
static bool IsValid3(string s)
{
    // 使用栈来检查括号的有效性
    Stack<char> stack = new Stack<char>();

    // 遍历字符串的每个字符
    foreach (char c in s)
    {
        // 如果是左括号,将其对应的右括号入栈
        if (c == '(')
        {
            stack.Push(')');
        }
        else if (c == '{')
        {
            stack.Push('}');
        }
        else if (c == '[')
        {
            stack.Push(']');
        }
        else
        {
            // 如果是右括号,检查栈顶元素是否与当前右括号匹配
            // 若匹配,弹出栈顶元素;否则,返回false
            if (stack.Count == 0 || stack.Pop() != c)
            {
                return false;
            }
        }
    }

    // 如果栈为空,说明所有括号都匹配成功
    return stack.Count == 0;
}

使用字典和栈验证括号

// 方法四:使用字典和栈验证括号
static bool IsValid4(string s)
{
    // 创建一个字典来存储左括号及其对应的右括号
    Dictionary<char, char> bracketDic = new Dictionary<char, char>
    {
        { '(', ')' }, // 圆括号匹配
        { '{', '}' }, // 花括号匹配
        { '[', ']' } // 方括号匹配
    };

    // 创建一个栈用于存储未匹配的左括号
    Stack<char> bracketStack = new Stack<char>();

    // 遍历字符串中的每个字符
    foreach (var charVal in s)
    {
        // 如果字符是左括号,则将其入栈
        if (bracketDic.ContainsKey(charVal))
        {
            bracketStack.Push(charVal);
        }
        else
        {
            // 如果字符是右括号,检查栈是否为空并且栈顶的左括号是否与当前右括号匹配
            if (bracketStack.Count > 0 && bracketDic[bracketStack.Peek()] == charVal)
            {
                // 如果匹配,将栈顶元素弹出
                bracketStack.Pop();
            }
            else
            {
                // 如果不匹配,返回 false
                return false;
            }
        }
    }

    // 如果栈为空,说明所有括号都匹配成功,返回 true;否则,返回 false
    return bracketStack.Count == 0;
}

20.3 代码

using System;

class Program
{
    static void Main()
    {
        #region 题目

        // 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
        // 有效字符串需满足:
        // 1. 左括号必须用相同类型的右括号闭合。
        // 2. 左括号必须以正确的顺序闭合。
        // 3. 每个右括号都有一个对应的相同类型的左括号。

        // 示例 1:
        // 输入:s = "()"
        // 输出:true

        // 示例 2:
        // 输入:s = "()[]{}"
        // 输出:true

        // 示例 3:
        // 输入:s = "(]"
        // 输出:false

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

        #endregion

        #region 测试

        // 示例 1
        string str1 = "()";
        bool result1 = IsValid1(str1);
        Console.WriteLine($"示例1 方法1 输出:{result1}");
        bool result1_2 = IsValid2(str1);
        Console.WriteLine($"示例1 方法2 输出:{result1_2}");
        bool result1_3 = IsValid3(str1);
        Console.WriteLine($"示例1 方法3 输出:{result1_3}");
        bool result1_4 = IsValid4(str1);
        Console.WriteLine($"示例1 方法4 输出:{result1_4}");

        // 示例 2
        string str2 = "()[]{}";
        bool result2 = IsValid1(str2);
        Console.WriteLine($"示例2 方法1 输出:{result2}");
        bool result2_2 = IsValid2(str2);
        Console.WriteLine($"示例2 方法2 输出:{result2_2}");
        bool result2_3 = IsValid3(str2);
        Console.WriteLine($"示例2 方法3 输出:{result2_3}");
        bool result2_4 = IsValid4(str2);
        Console.WriteLine($"示例2 方法4 输出:{result2_4}");

        // 示例 3
        string str3 = "(]";
        bool result3 = IsValid1(str3);
        Console.WriteLine($"示例3 方法1 输出:{result3}");
        bool result3_2 = IsValid2(str3);
        Console.WriteLine($"示例3 方法2 输出:{result3_2}");
        bool result3_3 = IsValid3(str3);
        Console.WriteLine($"示例3 方法3 输出:{result3_3}");
        bool result3_4 = IsValid4(str3);
        Console.WriteLine($"示例3 方法4 输出:{result3_4}");

        #endregion
    }

    #region 答案

    // 方法一:列表装左括号对比
    // 遍历字符串,是左括号就丢到列表里,是右括号的话就判断和列表尾部括号是否匹配
    static bool IsValid1(string s)
    {
        // 检查字符串长度是否为偶数,奇数长度的字符串无法满足括号闭合条件
        if (s.Length % 2 != 0) return false;

        // 用于存储左括号的列表
        List<char> leftBracketList = new List<char>();

        // 遍历输入字符串的每个字符
        for (int i = 0; i < s.Length; i++)
        {
            // 调用 ReturnLeftBracket 函数获取与当前右括号相匹配的左括号
            char leftBracket = ReturnLeftBracket(s[i]);

            // 如果返回的左括号不为空格,说明当前字符是右括号
            if (leftBracket != ' ')
            {
                // 检查 leftBracketList 中是否有左括号与当前右括号匹配
                if (leftBracketList.Count > 0 && leftBracketList[leftBracketList.Count - 1] == leftBracket)
                {
                    // 如果匹配成功,移除 leftBracketList 中的匹配左括号
                    leftBracketList.RemoveAt(leftBracketList.Count - 1);
                }
                else
                {
                    // 如果匹配失败,说明括号闭合顺序不正确,返回 false
                    return false;
                }
            }
            else
            {
                // 如果返回的左括号为空格,说明当前字符是左括号,将其添加到 leftBracketList 中
                leftBracketList.Add(s[i]);
            }
        }

        // 最终检查 leftBracketList 是否为空,若为空,则括号闭合成功,返回 true;否则,返回 false
        return leftBracketList.Count == 0;
    }

    // 根据右括号返回相应的左括号
    static char ReturnLeftBracket(char rightBracket)
    {
        switch (rightBracket)
        {
            case ')':
                return '(';
            case '}':
                return '{';
            case ']':
                return '[';
            default:
                return ' '; // 如果输入的不是右括号,则返回空格表示不匹配
        }
    }

    // 方法二:双栈弹出括号验证
    // 先把所有字符丢到一个字符栈中,循环弹出字符串判断是否是右括号,是右括号丢到右括号栈,是左括号弹出右括号栈顶元素看是否匹配
    static bool IsValid2(string s)
    {
        // 检查字符串长度是否为偶数,奇数长度的字符串无法满足括号闭合条件
        if (s.Length % 2 != 0) return false;

        // 用于存储字符的栈,按顺序将字符串的字符入栈
        Stack<char> bracketPushStack = new Stack<char>();

        // 将字符串的字符按顺序入栈
        for (int i = 0; i < s.Length; i++)
        {
            bracketPushStack.Push(s[i]);
        }

        // 用于存储右括号的栈
        Stack<char> rightBracketPopStack = new Stack<char>();

        // 遍历字符栈中的每个字符
        while (bracketPushStack.Count > 0)
        {
            // 弹出栈顶字符
            char nowBracket = bracketPushStack.Pop();

            // 如果是右括号,将其入右括号栈
            if (nowBracket == ')' || nowBracket == '}' || nowBracket == ']')
            {
                rightBracketPopStack.Push(nowBracket);
            }
            // 如果是左括号,进行匹配操作
            else if (nowBracket == '(' || nowBracket == '{' || nowBracket == '[')
            {
                // 如果右括号栈为空,说明没有匹配的右括号,返回 false
                if (rightBracketPopStack.Count == 0)
                {
                    return false;
                }

                // 调用 IsLeftBracketMatching 函数判断左右括号是否匹配
                bool isBracketMatching = IsLeftBracketMatching(nowBracket, rightBracketPopStack.Pop());

                // 如果不匹配,返回 false
                if (!isBracketMatching)
                {
                    return false;
                }
            }
            else
            {
                // 如果字符既不是左括号也不是右括号,返回 false
                return false;
            }
        }

        // 最终检查右括号栈是否为空,若为空,则括号闭合成功,返回 true;否则,返回 false
        return rightBracketPopStack.Count == 0;
    }

    // 判断左右括号是否匹配
    static bool IsLeftBracketMatching(char leftBracket, char rightBracket)
    {
        switch (leftBracket)
        {
            case '(':
                return rightBracket == ')';
            case '{':
                return rightBracket == '}';
            case '[':
                return rightBracket == ']';
            default:
                return false; // 如果输入的不是左括号,则返回 false
        }
    }

    // 方法三:单栈弹出括号验证
    // 遍历字符串,如果是左括号把对应的右括号丢进栈,是右括号就弹出栈判断是否相等
    static bool IsValid3(string s)
    {
        // 使用栈来检查括号的有效性
        Stack<char> stack = new Stack<char>();

        // 遍历字符串的每个字符
        foreach (char c in s)
        {
            // 如果是左括号,将其对应的右括号入栈
            if (c == '(')
            {
                stack.Push(')');
            }
            else if (c == '{')
            {
                stack.Push('}');
            }
            else if (c == '[')
            {
                stack.Push(']');
            }
            else
            {
                // 如果是右括号,检查栈顶元素是否与当前右括号匹配
                // 若匹配,弹出栈顶元素;否则,返回false
                if (stack.Count == 0 || stack.Pop() != c)
                {
                    return false;
                }
            }
        }

        // 如果栈为空,说明所有括号都匹配成功
        return stack.Count == 0;
    }


    // 方法四:使用字典和栈验证括号
    static bool IsValid4(string s)
    {
        // 创建一个字典来存储左括号及其对应的右括号
        Dictionary<char, char> bracketDic = new Dictionary<char, char>
        {
            { '(', ')' }, // 圆括号匹配
            { '{', '}' }, // 花括号匹配
            { '[', ']' } // 方括号匹配
        };

        // 创建一个栈用于存储未匹配的左括号
        Stack<char> bracketStack = new Stack<char>();

        // 遍历字符串中的每个字符
        foreach (var charVal in s)
        {
            // 如果字符是左括号,则将其入栈
            if (bracketDic.ContainsKey(charVal))
            {
                bracketStack.Push(charVal);
            }
            else
            {
                // 如果字符是右括号,检查栈是否为空并且栈顶的左括号是否与当前右括号匹配
                if (bracketStack.Count > 0 && bracketDic[bracketStack.Peek()] == charVal)
                {
                    // 如果匹配,将栈顶元素弹出
                    bracketStack.Pop();
                }
                else
                {
                    // 如果不匹配,返回 false
                    return false;
                }
            }
        }

        // 如果栈为空,说明所有括号都匹配成功,返回 true;否则,返回 false
        return bracketStack.Count == 0;
    }

    #endregion
}

20.4 运行结果

示例1 方法1 输出:True
示例1 方法2 输出:True
示例1 方法3 输出:True
示例1 方法4 输出:True
示例2 方法1 输出:True
示例2 方法2 输出:True
示例2 方法3 输出:True
示例2 方法4 输出:True
示例3 方法1 输出:False
示例3 方法2 输出:False
示例3 方法3 输出:False
示例3 方法4 输出:False


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏