题目描述如下:(文末有string类型的介绍)
本题是回文类题目中比较简答的一种,输入的字符串也只有“(”、“)”、“["、”]“、”{“、”}“六种,题目可以产生一些变形,如判断括号没有闭合等,该类题目是面试中常考的题目,解决的方法通常采用stack(栈)这种数据结构,stack是一种先进后出的结构,即first in last out,不熟悉栈的同学可以参考维基百科中栈的介绍,此处是地址 https://zh.wikipedia.org/wiki/%E5%A0%86%E6%A0%88
该题目的解答思路如下:(leetcode中的提示给出的思路很好,请大家参考。看完提示后,再看下面的思路效果更佳)
思路示例图如下:
- 遍历string,出现”(“、”{“、”[“ 则入栈,因为这些符号可能和其后面的符号成对匹配
- 遍历的过程中,如果遇到了”)“、”}“、”]" ,那么不能入栈,此时应该和栈顶的元素进行比较,如果成对匹配,那么弹栈
- 按照上面的两步一直进行下去,如果程序结束都栈中没有多余的元素,那么该string都是成对匹配的,返回true,否则返回false
一开始写的c++代码如下:
class Solution1 {
public:
bool isValid(string s) {
auto len = s.length();
if(len % 2)
return false;
if(len == 0)
return true;
stack<char> st;
st.push(s[0]);
int i = 0;
for(i = 1; i < len; i++) {
if(s[i] == '(' || s[i] == '[' || s[i] == '{' ) {
st.push(s[i]);
}
else {
//cout << st.top() << " " << s[i] << endl;
if(!st.empty() && isMatch(st.top(),s[i]))
st.pop();
}
}
if(st.empty())
return true;
else return false;
}
private:
bool isMatch(char s1, char s2) {
if(s1 == '(' && s2 == ')')
return true;
else if(s1 == '[' && s2 == ']')
return true;
else if(s1 == '{' && s2 == '}')
return true;
else return false;
}
};
代码虽然可以跑通,但是不够简明。在弹栈的时候一定要注意,此时栈不能为空,因此要提前进行判断。
一种更优化的c++代码写法如下:
//optime solution1
class Solution2{
public :
bool isValid(string s) {
if(s.length() == 0)
return true;
stack<char> st;
for(int i = 0; i < s.length(); i++) {
if(s[i] == '(' or s[i] == '[' or s[i] == '{') {
st.push(s[i]);
}
else if (s[i] == ')') {
if(st.empty() or st.top()!='(')
return false;
else
st.pop();
}
else if (s[i] == ']') {
if(st.empty() or st.top()!='[')
return false;
else
st.pop();
}
else if (s[i] == '}') {
if(st.empty() or st.top()!='{')
return false;
else
st.pop();
}
}
if(st.empty())
return true;
else
return false;
}
};
优化后的代码较之前要简明扼要,书写的时候不容易出错。在利用qt进行变异的时候,以上的代码还是有很多warning的,主要原因是stack和string中的有一些数据类型是不一样的,经常出现int到unsigned long等的强制类型转换。
一种更好的方法是直接利用string进行操作,而不是建立专门的栈。因为c++标准模板库中,string可以有stack.pop()等这样的功能。代码实现如下:
class Solution {
public:
bool isValid(string s) {
if(s.empty()) return true;
string o = "";
for (auto c : s){
if (c == '(' || c == '{' or c == '['){
o.push_back(c);
}
else if(c == ')'){
if(o.empty() || o.back() !='(') return false;
else o.pop_back();
}
else if(c == ']'){
if(o.empty() || o.back() !='[') return false;
else o.pop_back();
}
else if(c == '}'){
if(o.empty() || o.back() !='{') return false;
else o.pop_back();
}
}
return o.empty();
}
};
关于string的介绍,维基百科中的介绍详略得当,重点突出,易于立即理解 https://zh.wikipedia.org/wiki/String_(C%2B%2B%E6%A0%87%E5%87%86%E5%BA%93)
c++11以后,对for循环也进行了简化的操作。
https://zh.cppreference.com/w/cpp/language/range-for
上面是对“基于范围的for循环”的介绍,一段比较有代表性的代码是
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (const int& i : v) // 以 const 引用访问
std::cout << i << ' ';
std::cout << '\n';
for (auto i : v) // 以值访问, i 的类型是 int
std::cout << i << ' ';
std::cout << '\n';
for (auto& i : v) // 以引用访问, i 的类型是 int&
std::cout << i << ' ';
std::cout << '\n';
for (int n : {0, 1, 2, 3, 4, 5}) // 初始化器可以是花括号初始化列表
std::cout << n << ' ';
std::cout << '\n';
int a[] = {0, 1, 2, 3, 4, 5};
for (int n : a) // 初始化器可以是数组
std::cout << n << ' ';
std::cout << '\n';
for (int n : a)
std::cout << 1 << ' '; // 循环变量不必使用
std::cout << '\n';
}
c++ 11 让c++变得更加简单,在以后代码的书写中,要尽量多使用模板库,以及c++最新的功能。