给定一个仅包含 '('、')'、'{'、'}'、'['、']'的字符串,确定输入的字符串是否合法。

e.g. "()"、"()[]{}"、"[()]([]({}))" 是合法的,而"(]"、"([)]" 是不合法的。

使用栈stack

C++实现:

 bool isValid(string s) {
stack<char> stack;
for (char &c : s) {
if (c == '(')
stack.push(')');
else if (c == '{')
stack.push('}');
else if (c == '[')
stack.push(']');
else if (stack.empty() || (stack.top() != c))
return false;
else
stack.pop();
}
return stack.empty();
}

对应的Java实现:

 public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
for (char c : s.toCharArray()) {
if (c == '(')
stack.push(')');
else if (c == '{')
stack.push('}');
else if (c == '[')
stack.push(']');
else if (stack.isEmpty() || stack.pop() != c)  
return false;
}
return stack.isEmpty();
}

C++中的stack,其中有两个方法:

  • pop(),返回void,不返回类型<T>。
  • top(),返回栈顶的引用。

pop()不返回栈顶元素的原因是:

  • 异常安全原因

如果要实现,代码如下,

template<class T>
T stack<T>::pop() {
if( vused_ == ) {
throw "pop from empty stack";
} else {
return v_[--vused_ - ];
}
}

试图返回 v_[--vused_ - 1] 的时候,会调用 T 的拷贝构造函数,如果调用的时候发生异常,并没有返回正确的值,但是栈顶元素已经弹出了,这时就丢失了栈顶数据。

如果这样写,

template<class T>
T stack<T>::pop() {
if( vused_ == ) {
throw "pop from empty stack";
} else {
T result = v_[vused_ - ];
--vused_;
return result;
}
}

先建立一个栈顶元素的副本,如果拷贝构造函数出现异常,那么 --vused_ 不会执行,就不会丢失数据。但假如 --vused_ 和 return result 之间发生异常,依然会出问题。也就是说,如果想同时做 pop() 和 top() ,一定要保证 --vused_ 和 return result 是一个执行事务。

  • 效率原因

因为栈顶元素在栈中已经不存在,必须在按引用返回之前现将其存储到某个地方。如果选用动态内存,除非动态内存最终被删除,否则将导致内存泄露。

如果调用拷贝构造函数,对象按值传递的方式从函数返回,效率低下。

扩展 生成括号

给定 n 对括号,写出所有可能的合法括号组合。

e.g. 给定 n = 3,结果集为

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

我的思路是递归

 vector<string> generateParenthesis(int n) {
if (n == ) {
return {"()"};
} else {
vector<string> result;
vector<string> pre = generateParenthesis(n - );
for (int i = ; i < pre.size(); i++) {
result.push_back("(" + pre[i] + ")");
result.push_back(pre[i] + "()");
if ("()" + pre[i] != pre[i] + "()")
result.push_back("()" + pre[i]);
}
return result;
}
}

算法没什么问题,可以生成所有可能的括号集合,但 vector 中存储的顺序不论怎么改都和答案的不一样。

答案使用的思路是DFS。创建一个函数来增加括号,str 表示加入到结果 vector<string> res 中的一项。

left 表示剩下的需要增加的“ ( ”的个数,初始为 n;right 表示当前的 str 中需要与没有配对的 “ ( ” 配对的 “ ) ” 的个数。

若 left > 0,则在 str 里加入一个“ ( ”,并让下次需要增加的“ ( ”的个数减 1,且因为加入了一个“ ( ”,该左括号没有右括号与之配对,所以当前 str 需要的“ ) ”加 1;

若 right > 0,说明需要在 str 里加入一个“ ) ”,下次需要的“ ) ”少 1 个就行了。

 vector<string> generateParenthesis(int n) {
vector<string> result;
addParen(result, "", n, );
return result;
} void addParen(vector<string> &res, string str, int left, int right) {
if (left == && right == ) {
res.push_back(str);
return;
}
if (left > )
addParen(res, str + "(", left - , right + );
if (right > )
addParen(res, str + ")", left, right - );
}

类似的,

这种方法个人觉得比上面的直观,一项 str 需要 n 个左括号和 n 个右括号,那么 left 和 right 都直接表示 str 所需要的“ ( ”和“ ) ”的个数。

注意的是,str 中一定要有没有配对的 “ ( ” 存在,才能加入 “ ) ”,所以加入右括号的判断条件是 if (right > left)。

 vector<string> generateParenthesis(int n) {
vector<string> result;
addParen(result, "", n, n);
return result;
} void addParen(vector<string> &res, string str, int left, int right) {
if (left == && right == ) {
res.push_back(str);
return;
}
if (left > )
addParen(res, str + "(", left - , right);
if (right > left)
addParen(res, str + ")", left, right - );
}

将 str 使用引用传参的话则不需要建立许多局部临时变量 str,可以节省一定的空间。

 vector<string> generateParenthesis(int n) {
vector<string> result;
string str = "";
addParen(result, str, n, n);
return result;
} void addParen(vector<string> &res, string &str, int left, int right) {
if (left == && right == ) {
res.push_back(str);
return;
}
if (left > ) {
str += "(";
addParen(res, str, left - , right);
str.resize(str.length() - );
}
if (right > left) {
str += ")";
addParen(res, str, left, right - );
str.resize(str.length() - );
}
}

注意 16 和 21 行 str.resize(str.length() - 1); 语句调用,由于 str 是引用,如果不重新设置 str 长度,str 会越来越长。

使用 pop_back 也可以

if (left > ) {
str.push_back('(');
addParen(res, str, left - , right);
str.pop_back();
}
if (right > left) {
str.push_back(')');
addParen(res, str, left, right - );
str.pop_back();
}

【LeetCode】Valid Parentheses合法括号的更多相关文章

  1. [LeetCode] 20. Valid Parentheses 合法括号

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  2. [LeetCode] Valid Parentheses 验证括号

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  3. [Leetcode] valid parentheses 有效括号对

    Given a string containing just the characters'(',')','{','}','['and']', determine if the input strin ...

  4. LeetCode Valid Parentheses 有效括号

    class Solution { public: void push(char c){ //插入结点 struct node *n=new struct node; n->nex=; n-> ...

  5. [leetcode]20. Valid Parentheses有效括号序列

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  6. [LeetCode] 20. Valid Parentheses 验证括号

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  7. [LeetCode] Generate Parentheses 生成括号

    Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...

  8. [LintCode] Valid Parentheses 验证括号

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  9. LeetCode: Valid Parentheses 解题报告

    Valid Parentheses Given a string containing just the characters '(', ')', '{', '}', '[' and ']', det ...

随机推荐

  1. 【NOIP 2015】Day2 T3 运输计划

    Problem Background 公元 \(2044\) 年,人类进入了宇宙纪元. Description 公元\(2044\) 年,人类进入了宇宙纪元. $L $国有 \(n\) 个星球,还有 ...

  2. HDU 5242 Game(贪心)

    http://acm.hdu.edu.cn/showproblem.php?pid=5242 题意: 给出一棵树,每个节点都有一个权值,每次可以获得从根结点(1)到叶子节点上的所有权值和,每个节点只能 ...

  3. Js操作Cookie的实现

  4. 给 layui upload 带每个文件的进度条, .net 后台代码

    1.upload.js 扩展 功能利用ajax的xhr属性实现该功能修改过modules中的upload.js文件功能具体实现:在js文件中添加监听函数 //创建监听函数 var xhrOnProgr ...

  5. 前端如何应对笔试算法题?(用node编程)

    用nodeJs写算法题 咱们前端使用算法的地方不多,但是为了校招笔试,不得不针对算法题去练习呀! 好不容易下定决心 攻克算法题.发现js并不能像c语言一样自建输入输出流.只能回去学习c语言了吗?其实不 ...

  6. 转youhu科技的文章 勿怪 感激 感激

    资源加载 资源加载是加载模块中最为耗时的部分,其CPU开销在Unity引擎中主要体现在Loading.UpdatePreloading和Loading.ReadObject两项中,相信经常查看Prof ...

  7. 传的参数是url地址时需要特殊处理

    <a href="javascript:;" data-url="{$vo.url}" class="info_generate_qr" ...

  8. MySQL 的 DISTINCT 应用于2列时

    SELECT DISTINCT vend_id告诉MySQL只返回不同(唯一)的 vend_id行,也就是在vend_id 有重复的行中,只保留一行,其他的不作输出.比如我创建了如下的student表 ...

  9. 总要先爬出坑的JEE架构

    先来看看官网对它的定义. Java平台企业版(Java EE)是社区驱动的企业软件的标准.Java EE是使用Java Community Process开发的,其中包括来自行业专家,商业和开源组织, ...

  10. TCP与UDP各自优缺点与区别

    TCP的优点: 可靠,稳定 TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认.窗口.重传.拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源. TCP的缺 ...