6.有效的括号

本文详细介绍了如何使用栈数据结构解决有效括号字符串的问题。通过遍历输入字符串,遇到左括号压栈,遇到右括号时检查栈顶元素是否与其匹配,匹配则出栈,不匹配则返回错误。最终栈为空则表示所有括号匹配成功。

一、题目描述

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

左括号必须用相同类型的右括号闭合。

左括号必须以正确的顺序闭合

在这里插入图片描述
在这里插入图片描述

二、解题思路

可以利用栈(先进后出),总共就三种类型的括号,我们将每一种括号的左半边存入到栈中,然后我们分别将字符串中剩下的每种括号的右半边与栈顶元素进行比较,如果能匹配上就将栈顶元素弹出,此时再进行当前栈顶元素的判断。

三、代码编写步骤

第一步:先声明一个字符串类型的栈,然后遍历栈中的每一个字符,将字符中的每种括号的左半边存储到栈中。

第二步:然后进行判断,列举出每一种匹配的条件,当满足某一种条件之后将其出栈。

四、代码演示

class Solution {
    public boolean isValid(String s) {
        //定义一个用来装字符类型的栈
        Stack<Character> stack = new Stack<>();
        for(int i=0; i<s.length(); i++){
            char c = s.charAt(i);
             //如果拿到的s中的元素是左边的括号类型就压栈
            if(c == '(' || c=='[' || c=='{'){
                stack.push(c);
            }else{
                /*
                *在栈中有元素的情况下:在s中拿到的右边类型的元素和这个栈顶元素
                *做个比较
                */
                if(!stack.isEmpty()){
                    //看看栈顶的元素
                    char top = stack.peek();
                    //如果栈顶元素可以和‘)’配对,那就让栈顶元素出栈
                    if(c==')'&& top=='('){
                        stack.pop();
                    }else if(c==']'&&top=='['){
                        stack.pop();
                    }else if(c=='}'&&top=='{'){
                        stack.pop();
                    }else{
                        return false;
                    }
                }else{
                    return false;
                }
            }
        }
        //最后,如果栈空了那就说明都匹配上了,如果栈里还有元素。
        return stack.isEmpty();
    }
}

第4行:定义一个用来装字符类型的栈。

第6行:遍历字符串s,获取第i个位置的字符

第8行:进行判断,如果拿到的第i个位置的字符是左边括号类型就压栈

第9行:进栈操作,就是将左边的字符压如栈中。

第15行:栈的非空判断,就是说如果栈里面有元素,那么进入下面的操作

第17行:stack.peek() 取出栈顶值,不出栈,将栈顶值赋给top

第19到24行:在下一次循环取出的某个字符能与栈顶匹配的话,就stack.pop(),该方法用于从堆栈中弹出元素,该元素从堆栈顶部弹出,并从堆栈顶部移除。

第34行:如果栈空了那就说明都匹配上了,如果栈里还有元素,继续上面你的方法。

总结

新手小白自己的一些见解,可能还有更好的方法或者效率更高的方法,不足之处还望指正。

# 题目重述 在原有C++语法检查器的基础上,增加以下**六个加分项功能**: 1. 双引号不配对情况(如字符串未闭合); 2.括号 `{}` 匹配情况; 3.括号 `[]` 匹配情况; 4. 条件语句括号检查(如 `if`, `for`, `while` 是否缺少控制括号); 5. 转义字符检查(如 `"Line \"test\""` 中的合法转义); 6. 数字格式检查(如非法数字 `12a`, `0..5` 等); 需在原有必选功能基础上集成以上功能,并输出到结果文件中。 --- # 代码概述 本代码是在原语法检查器基础上的**增强版本**,新增了六项高级语法检查功能。整体结构仍基于面向对象设计,使用 `CGramCheck` 类封装全部逻辑,利用栈式思想实现各种括号与引号的匹配检测,同时加入词法分析模块用于识别数字格式和转义序列。 --- # 代码解析 ```cpp #include <iostream> #include <fstream> #include <string> #include <vector> #include <cctype> #include <stack> #include <cctype> #include <algorithm> using namespace std; /** * 自定义队列类(同原题要求) */ class CQueue { public: CQueue(int nInitSize, int nIncStep) : m_nSize(0), m_nIncStep(nIncStep) { m_pBuf = new string[nInitSize]; m_nCapacity = nInitSize; } ~CQueue() { delete[] m_pBuf; } bool in(string ele) { if (m_nSize >= m_nCapacity) { int newSize = m_nCapacity + m_nIncStep; string* temp = new string[newSize]; for (int i = 0; i < m_nSize; ++i) temp[i] = m_pBuf[i]; delete[] m_pBuf; m_pBuf = temp; m_nCapacity = newSize; } m_pBuf[m_nSize++] = ele; return true; } bool out(string& ele) { if (m_nSize == 0) return false; ele = m_pBuf[0]; for (int i = 1; i < m_nSize; ++i) m_pBuf[i - 1] = m_pBuf[i]; --m_nSize; return true; } int size() const { return m_nSize; } private: string* m_pBuf; int m_nSize; int m_nCapacity; int m_nIncStep; }; /** * 增强版语法检查类,支持全部加分项 */ class CGramCheck { public: CGramCheck() : lineCount(0), errorCount(0) {} void check() { ifstream inFile("tobecheck.cpp"); ofstream outFile("checkres.txt", ios::out | ios::trunc); if (!inFile.is_open()) { cout << "Error: tobecheck.cpp not found!" << endl; return; } string line; vector<string> lines; while (getline(inFile, line)) { lines.push_back(line); } inFile.close(); lineCount = static_cast<int>(lines.size()); // 初始化各项错误计数 int semicolonMissing = 0; int hashMissing = 0; int singleQuoteUnpaired = 0; int doubleQuoteUnpaired = 0; int blockCommentUnpaired = 0; int braceMismatch = 0; int bracketMismatch = 0; int parenMismatch = 0; int conditionParenIssue = 0; int invalidNumberFormat = 0; int escapeCharError = 0; bool inBlockComment = false; stack<char> quoteStack; // ' 和 " stack<char> braceStack; // { } stack<char> bracketStack; // [ ] stack<char> parenStack; // ( ) for (size_t i = 0; i < lines.size(); ++i) { const string& l = lines[i]; string trimmed = trim(l); // 忽略空行和纯注释行 if (trimmed.empty() || startsWith(trimmed, "//")) continue; // ========== 2.a 分号缺失 ========== if (isStatementLine(trimmed) && !endsWith(trimmed, ";") && !startsWith(trimmed, "#")) { semicolonMissing++; } // ========== 2.b 头文件缺 # ========== if (isPartOfIncludeDirective(trimmed) && !startsWith(trimmed, "#")) { hashMissing++; } // ========== 2.c 单引号配对 + 新增:双引号配对 ========== processQuotes(l, quoteStack, doubleQuoteUnpaired, singleQuoteUnpaired); // ========== 2.d 块注释 /* */ 配对 ========== processBlockComments(l, inBlockComment); // ========== 新增:花括号 {} ========== for (char c : l) { if (c == '{') braceStack.push(c); else if (c == '}') { if (braceStack.empty()) braceMismatch++; else braceStack.pop(); } } // ========== 新增:方括号 [] ========== for (char c : l) { if (c == '[') bracketStack.push(c); else if (c == ']') { if (bracketStack.empty()) bracketMismatch++; else bracketStack.pop(); } } // ========== 新增:圆括号 () ========== for (char c : l) { if (c == '(') parenStack.push(c); else if (c == ')') { if (parenStack.empty()) parenMismatch++; else parenStack.pop(); } } // ========== 新增:条件语句括号检查 ========== if ((startsWith(trimmed, "if") || startsWith(trimmed, "while") || startsWith(trimmed, "for")) && !hasBalancedControlParentheses(trimmed)) { conditionParenIssue++; } // ========== 新增:数字格式检查 ========== invalidNumberFormat += countInvalidNumbers(trimmed); // ========== 新增:转义字符检查 ========== escapeCharError += checkEscapeSequences(l); } // 最终判断未闭合 if (!quoteStack.empty()) doubleQuoteUnpaired += static_cast<int>(quoteStack.size()); if (!braceStack.empty()) braceMismatch += static_cast<int>(braceStack.size()); if (!bracketStack.empty()) bracketMismatch += static_cast<int>(bracketStack.size()); if (!parenStack.empty()) parenMismatch += static_cast<int>(parenStack.size()); if (inBlockComment) blockCommentUnpaired = 1; // 写入检查结果 outFile << "Total lines: " << lineCount << endl; outFile << "Syntax errors found:" << endl; outFile << "Semicolon missing: " << semicolonMissing << endl; outFile << "Hash (#) missing in include: " << hashMissing << endl; outFile << "Single quote unpaired: " << singleQuoteUnpaired << endl; outFile << "Double quote unpaired: " << doubleQuoteUnpaired << endl; outFile << "Block comment /* */ unpaired: " << blockCommentUnpaired << endl; outFile << "Brace {} mismatch: " << braceMismatch << endl; outFile << "Bracket [] mismatch: " << bracketMismatch << endl; outFile << "Parentheses () mismatch: " << parenMismatch << endl; outFile << "Condition/control parentheses issue: " << conditionParenIssue << endl; outFile << "Invalid number format: " << invalidNumberFormat << endl; outFile << "Invalid escape sequence: " << escapeCharError << endl; outFile.close(); errorCount = semicolonMissing + hashMissing + singleQuoteUnpaired + doubleQuoteUnpaired + blockCommentUnpaired + braceMismatch + bracketMismatch + parenMismatch + conditionParenIssue + invalidNumberFormat + escapeCharError; cout << "Grammar check completed." << endl; cout << "Total lines: " << lineCount << endl; cout << "Total errors: " << errorCount << endl; } private: int lineCount; int errorCount; string trim(const string& s) { size_t start = s.find_first_not_of(" \t\r\n"); if (start == string::npos) return ""; size_t end = s.find_last_not_of(" \t\r\n"); return s.substr(start, end - start + 1); } bool startsWith(const string& s, const string& prefix) { return s.rfind(prefix, 0) == 0; } bool endsWith(const string& s, const string& suffix) { if (suffix.length() > s.length()) return false; return s.compare(s.length() - suffix.length(), suffix.length(), suffix) == 0; } bool isStatementLine(const string& line) { return !(startsWith(line, "if") || startsWith(line, "for") || startsWith(line, "while") || starts(line, "switch") || startsWith(line, "//") || startsWith(line, "/*") || startsWith(line, "*") || startsWith(line, "#")); } bool isPartOfIncludeDirective(const string& line) { return line.find("include") != string::npos && (line.find("<") != string::npos || line.find("\"") != string::npos); } void processQuotes(const string& line, stack<char>& quoteStack, int& doubleUnpaired, int& singleUnpaired) { for (size_t i = 0; i < line.length(); ++i) { char c = line[i]; if (c == '\\' && i + 1 < line.length()) { i++; // 跳过转义字符后一个字符 continue; } if (c == '\'' || c == '"') { if (!quoteStack.empty() && quoteStack.top() == c) { quoteStack.pop(); } else { quoteStack.push(c); } } } } void processBlockComments(const string& line, bool& inBlockComment) { size_t pos = 0; while ((pos = line.find("/*", pos)) != string::npos) { if (!inBlockComment) { inBlockComment = true; pos += 2; } else { pos += 2; } } while ((pos = line.find("*/", pos)) != string::npos) { if (inBlockComment) { inBlockComment = false; pos += 2; } else { pos += 2; } } } bool hasBalancedControlParentheses(const string& line) { size_t start = line.find('('); if (start == string::npos) return false; int count = 0; for (size_t i = start; i < line.length(); ++i) { if (line[i] == '(') count++; else if (line[i] == ')') { count--; if (count == 0) return true; } } return false; // 未找到闭合 } int countInvalidNumbers(const string& line) { int badCount = 0; size_t i = 0; while (i < line.length()) { if (isdigit(line[i])) { size_t j = i; bool hasDot = false; while (j < line.length() && (isdigit(line[j]) || line[j] == '.')) { if (line[j] == '.') { if (hasDot) break; // 多个小数点 hasDot = true; } j++; } // 检查是否为有效数字结尾 if (j > i) { string num = line.substr(i, j - i); if (num == "." || num.find("..") != string::npos) { badCount++; } else if (hasDot && (num.front() == '.' && !isdigit(num[1]))) { badCount++; } } i = j; } else { i++; } } return badCount; } int checkEscapeSequences(const string& line) { int err = 0; for (size_t i = 0; i < line.length(); ++i) { if (line[i] == '\\') { if (i + 1 >= line.length()) { err++; } else { char next = line[i + 1]; if (strchr("abfnrtv\\'\"", next)) { i++; // 合法 } else if (next == 'x') { // hex escape \x.. i += 2; if (i >= line.length() || !isxdigit(line[i])) err++; } else if (isdigit(next)) { // octal escape int cnt = 0; while (i + 1 < line.length() && isdigit(line[i + 1]) && cnt < 3) { i++; cnt++; } } else { err++; // 无效转义 } } } } return err; } }; int main() { CGramCheck checker; checker.check(); return 0; } ``` --- # 知识点(列出该代码中遇到的知识点) 1. **栈结构用于符号匹配** 利用 `stack<char>` 检查 `{}`, `[]`, `()`, `''`, `""` 是否成对出现,避免嵌套错误。 2. **词法分析基础(数字与转义)** 手动遍历字符串识别数字模式与转义序列,区分合法与非法格式。 3. **字符串处理与状态机思想** 在复杂文本中提取语法特征,结合状态标志(如注释、引号)进行上下文判断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值