一、题目描述
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
示例 4:
输入:s = "([])"
输出:true
提示:
1 <= s.length <= 104
s
仅由括号'()[]{}'
组成
二、分析
输入:一个string
输出:一个bool
目的:检查输入的string是否符合:1.左括号必须用相同类型的右括号闭合。2.左括号必须以正确的顺序闭合。3.每个右括号都有一个对应的相同类型的左括号。同时也需设置输入的合法性检查
初步想法:
首先创建两套映射,分别实现:将括号的左右映射成布尔类型、将三种类型的括号映射成表示优先顺序的数字。同时,对括号组合有效性的判断大概是这样:“最后读到的左括号会尝试匹配最先读到的右括号”,与栈的后进先出规则相似,所以创建一个栈,按字符读取string并以优先数形式存放括号,在读取到左括号时压入栈,在读到右括号时弹出栈顶元素,判断栈顶元素和读到的括号是否为同一类型的括号,若否则return false,是则继续读入下一个括号直到读完所有输入括号;然后检查栈内是否还有元素,若有则return false,无则return true;
新知识:
1.在计算机科学和大多数编程语言中括号的优先顺序通常是:
圆括号 ():最高优先级,用于函数调用和控制表达式的求值顺序。
方括号 []:中间优先级,用于访问数组或列表的元素。
大括号 {}:最低优先级,用于定义代码块或数据结构。
所以正确的顺序应该是这样:([{}])
2.映射和转换:当需要将一种类型的数据映射到另一种类型的数据时,可以使用unordered_map,unordered_map是C++标准库中的一个关联容器,用于存储键值对(key-value pairs)。与map 不同,unordered_map是基于哈希表实现的,因此它不保证键值对的有序性,但提供了平均时间复杂度为 O(1) 的插入、查找和删除操作。像这样:
int main() {
std::unordered_map<std::string, int> stringToInt = {
{"one", 1},
{"two", 2},
{"three", 3}
};
std::string input = "two";
if (stringToInt.find(input) != stringToInt.end()) {
std::cout << "The number for " << input << " is " << stringToInt[input] << std::endl;
} else {
std::cout << "Input not found." << std::endl;
}
return 0;
}
出错的地方和遇到的困难:
1.在每次访问stack.top()时要先排除stack为空的情况
2.像for (char c : s) 这样的范围基遍历(Range-based for loop)遍历值得学习,也被称为基于范围的 for 循环。这种语法是从 C++11 开始引入的,旨在简化对容器或数组的遍历。还可以这么写:
int arr[] = {1, 2, 3, 4, 5};
for (int i : arr) {
std::cout << i << std::endl;
}
vector<int> vec = {1, 2, 3, 4, 5};
for (int i : vec) {
std::cout << i << std::endl;
}
3.貌似在计算机科学中括号的优先级在括号匹配问题中并不影响括号的有效性。括号的有效性主要关注的是括号的匹配和嵌套是否正确,而不是它们的优先级。所以像这样的输入"{[]}"其实是有效的,如果考虑其中括号的优先级认为优先级较高的中括号不能放在优先级较低的大括号中则会将这个输入判定无效。故一开始设置的两个映射就错误了,不需要安排三种括号之间的优先级,只需要设计一个将三种括号的左括号映射成对应的右括号的映射应该就足够了。所以这里存放一下旧版设置两种映射而出错的代码:
#include <stack>
#include <unordered_map>
unordered_map<char, bool> is_left = { // 用于区分括号左右的映射
{'(',true},
{'[',true},
{'{',true},
{')',false},
{']',false},
{'}',false}
};
unordered_map<char, int> priority = { // 用于标记括号优先顺序的映射
{'(',3},
{'[',2},
{'{',1},
{')',3},
{']',2},
{'}',1}
};
class Solution {
public:
bool isValid(string s) {
if(s=="") return false;
stack<int> stack; // 栈内将会是这样的情况:321
char temp;
int temp_priority = 0;
for(int i=0; i<s.length(); i++){
temp = s[i];
temp_priority = priority[temp]; // 存放当前括号的优先顺序,方便比较
if(is_left[temp]){ // 当读到左括号时
if(!stack.empty() && temp_priority>stack.top()) return false; // 读到的括号优先顺序大于当前栈顶括号时代表输入无效
else{
stack.push(temp_priority); // 将左括号以优先数形式存入
}
}
else if(!is_left[temp]){ // 当读到右括号时
if (stack.empty() || priority[temp] != stack.top()) return false; // 如果栈为空和当前栈顶括号不匹配则代表无效
else{
stack.pop(); // 弹出栈顶元素
}
}
}
if(!stack.empty()) return false; // 读完所有括号后栈内还有未弹出的括号代表有括号没匹配上,输入无效
return true;
}
};
三、代码实现
#include <stack>
#include <unordered_map>
#include <string>
unordered_map<char, char> bracket_map = { // 用于匹配括号
{'(', ')'},
{'[', ']'},
{'{', '}'}
};
class Solution {
public:
bool isValid(string s) {
if (s.empty()) return false;
stack<char> stack;
for (char c : s) {
if (bracket_map.count(c)) { // 当读到左括号时
stack.push(c); // 将左括号压入栈
} else { // 当读到右括号时
if (stack.empty() || bracket_map[stack.top()] != c) return false; // 如果栈为空或当前栈顶括号不匹配则代表无效
stack.pop(); // 弹出栈顶元素
}
}
return stack.empty(); // 读完所有括号后栈内还有未弹出的括号代表有括号没匹配上,输入无效
}
};