leetcode: Longest Valid Parentheses分析和实现
题目大意:给出一个只包含字符'('和')'的字符串S,求最长有效括号序列的长度。
很有趣的题目,有助于我们对这种人类自身制定的规则的深入理解,可能我们大多数人都从没有真正理解过怎样一个括号序列是有效的,因此解题也无从说起。整道题目的难度在于我们对有效括号序列的理解和定义。下面给出我自己的定义:、
定义1:空括号序列是有效的。
定义2:对于一对左右括号,若左括号出现在右括号的左边,且左右括号之间(不包含两端)的括号序列是有效的,那么称该左括号到该右括号(包含)这一段序列是有效的。且称该左括号和右括号匹配。
定义3:若一个括号序列中每一个左括号都有与之匹配的右括号,而每一个右括号也有与之匹配的左括号,则称该括号序列是有效的。定义3是对定义2的一个扩展。
对于定义的正确性与个人思维方式有关故不做说明,我一直认为无法证明是错误的东西,就是正确的,至少你能直接拿过来使用。下面给出一些记号的定义:S[x~y]表示由S[x],S[x+1],...,S[y-1],S[y]按先后顺序组成的子序列;n表示S的长度。后面不再对这些记号做说明。
命题1:对于任意一个有效括号序列P,其中每一个左括号唯一匹配一个右括号,同时右括号也唯一匹配左括号。
证明:定义3已经给出了有效序列中每个左括号与某个右括号匹配,只是缺少唯一性的证明,下面进行说明。假设对于某个下标为A的左括号同时下标为B与下标为C的两个右括号相匹配。不妨假设B<C。则由于A和B相匹配,由定义2可以得出序列P[A+1~C-1]是有效序列,而A+1<=B<=C-1,故能为找到下标为D的左括号,使得A+1<=D<B成立,且D与B想匹配(定义3)。可以重复上面的过程找到下标为E的右括号使得D<E<B,且D与E相匹配,从而无限推导下去,但是我们所考察的有效区间从A,C转为A,B,之后转为E,B,这是一个不断递减的过程,因此这个重复动作总会在某个点失败,而这时候就能反证假设错误,故唯一性得证。
命题1':若P和P[x~y]均为有效序列,那么在P中下标为x的左括号必然与下标为y的右括号唯一匹配。
证明:首先由于P[x~y]是有效序列,因此显然在P中下标为x的左括号与下标为y的右括号是匹配的。而由命题1即可直接得出匹配的唯一性。
命题2:对于一段括号序列S[x~y]是有效的等价于:若对于任意满足x <= i <= y的整数i,有S[x~i]中左括号数不少于右括号数以及S[i~y]中右括号数不少于左括号数两个性质同时成立。
证明:
对于必要性,由于S[x~y]中每一个左括号都有对应的右括号与之唯一相匹配,因此对于任意满足x <= i <= y的整数i,有S[x~i]中左括号数不少于右括号数(否则S[x~i]中多余的右括号则在S[x~y]没有与之匹配的左括号)。而S[i~y]中右括号数不少于左括号数性质也可以类似推出。
而对于充分性,利用数学归纳法。当y = x + 1时,命题显然成立,因为满足这一条件的子序列只可能是"()"。现假设y <= x + t时(t >= 1),命题成立。对于任意在S[x~y]之间出现的左括号,记其下标为L。由于S[L~y]中右括号不少于左括号数,因此必能找到最小的下标R,使得L<R且S[L~R]中出现的左括号数和右括号数数量一致。下面验证L和R是匹配的。首先L<R是不言而喻的,只要证明S[L+1~R-1]是有效的。由于下标R最小,因此可以得到对于任意满足L<m<R的整数m,都有S[L~m]中左括号数多于右括号数,否则与R的定义相悖。而同样能保证L是最大的满足L<R且S[L~R]中左括号与右括号数目一致的下标(利用反证法,设可以找到L<K<R使得S[K~R]中左括号与右括号数目一致,那么必然有S[L~K-1]中左括号与右括号数目一致),故对应的可以得出S[m~R]中右括号多于左括号数。利用这两个性质可以等价得出:对于任意满足L+1<=m<=R-1的整数m,都有S[L+1~m]中左括号数多于右括号数且S[m~R-1]中右括号多于左括号数。而(R-1)-(L+1)=R-L-2且y<=x+t+2可以推出R<=L+t,因此利用前面数学归纳法得到的结论(假设y <= x + t时命题成立)可以推出S[L+1~R-1]有效,即S[L~R]是有效的,再借助定义3可以得出序列S[x~y]是有效的。命题得证。
命题3:若S[A~B]是有效序列,且S[B+1~C]是有效序列,则S[A~C]也是有效序列。
证明:S[A~B]有效且S[B+1~C]是有效序列,则S[A~C]必然满足命题2右边的性质,故S[A~C]是有效序列。
命题3':若S[A~C]是有效序列,且对于A<B<C,S[A~B]是有效序列,则S[B+1~C]是有效序列。
证明:依旧是利用命题2右边的性质可以直接得出S[B+1~C]是有效序列。
本来考虑的时候是希望能利用命题2给出的结论进行快速计算,后来发现动态规划似乎更加简单,也更容易证明。创建长度为n的数组DP,令DP[i]记录以下标i作为左边界的最大有效括号序列的长度,可以发现下面的递推关系:
1.若S[i]是右括号,则DP[i]=0
2.若S[i]是左括号,且S[i+1]是右括号,则DP[i]=2+DP[i+2]
3.若S[i]是左括号,且S[i+1]是左括号,且S[DP[i+1]+i+1]是右括号,则DP[i]=DP[i+1]+2+DP[DP[i+1]+i+2]
4.若S[i]是左括号,且S[i+1]是左括号,且S[DP[i+1]+i+1]是左括号,则DP[i]=0
下面进行正确性的说明。
1的正确性不言而喻。
对于2,由于序列S[i~i+1+DP[i+2]]满足命题2右边的条件,因此序列有效。假设存在j > i + 1 + DP[i+2],使得S[i~j]有效,那么命题3'将导出S[i+2~j]是有效序列这样一个结论,这与DP的定义相悖。
对于3,同样序列满足S[i~i+1+DP[i+1]]命题2右边的条件,因此序列有效。根据命题1',此时S[i]与S[DP[i+1]+i+1]唯一匹配。若我们忽略S[i+1~i+DP[i+1]]部分内容,则可以归结为情况2,利用相同的思路证明即可。
对于4,能与左括号S[i]匹配的右括号的下标j只可能位于i+1与DP[i+1]+i+1(否则命题3'将导出与DP的定义相悖的结论)。而由于j不可能是DP[i+1]+i+1,因此j取i+1与DP[i+1]+i之间。但是由于i+1与DP[i+1]+i之间的任意下标为k的右括号,都必然会导出S[i~k]中左括号数多于右括号数目的现象,因此不存在与S[i]相匹配的右括号。
利用上面的递推公式和动态规划的技术,可以在O(n)的时间复杂度和空间复杂度内得到最终结果,最长的有效序列的长度。
下面给出实际代码:
package cn.dalt.leetcode; /** * Created by dalt on 2017/8/26. */ public class LongestValidParentheses { private static final char LEFT = '('; private static final char RIGHT = ')'; public int longestValidParentheses(String s) { int n = s.length(); char[] data = s.toCharArray(); int[] dp = new int[n + 1]; int max = 0; for (int i = n - 1; i >= 0; i--) { int nextIndex = i + 1; //condition 1 if (data[i] == RIGHT) { dp[i] = 0; } //check for not exceeding the bound else if (nextIndex >= n) { dp[i] = 0; } //condition 2 else if (data[nextIndex] == RIGHT) { dp[i] = dp[i + 2] + 2; } //condition 3 and 4 else if (data[nextIndex] == LEFT) { int endIndex = dp[nextIndex] + nextIndex; //check for not exceeding the bound if (endIndex >= n || data[endIndex] == LEFT) { dp[i] = 0; } //conditon 4 else { //DP[i]=DP[i+1]+2+DP[DP[i+1]+i+2] dp[i] = dp[nextIndex] + 2 + dp[endIndex + 1]; } } if (dp[i] > max) { max = dp[i]; } } return max; } }
leetcode: Longest Valid Parentheses分析和实现的更多相关文章
- [LeetCode] Longest Valid Parentheses 最长有效括号
Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...
- [LeetCode] Longest Valid Parentheses 解题思路
Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...
- [Leetcode] longest valid parentheses 最长的有效括号
Given a string containing just the characters'('and')', find the length of the longest valid (well-f ...
- [LeetCode] Longest Valid Parentheses
第一种方法,用栈实现,最容易想到,也比较容易实现,每次碰到‘)’时update max_len,由于要保存之前的‘(’的index,所以space complexity 是O(n) // 使用栈,时间 ...
- [LeetCode] Longest Valid Parentheses 动态规划
Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...
- LeetCode: Longest Valid Parentheses 解题报告
Longest Valid Parentheses Given a string containing just the characters '(' and ')', find the length ...
- [LeetCode] Longest Valid Parentheses -- 挂动态规划羊头卖stack的狗肉
(Version 1.3) 这题在LeetCode上的标签比较有欺骗性,虽然标签写着有DP,但是实际上根本不需要使用动态规划,相反的,使用动态规划反而会在LeetCode OJ上面超时.这题正确的做法 ...
- leetcode Longest Valid Parentheses python
class Solution(object): def longestValidParentheses(self, s): """ :type s: str :rtype ...
- [LeetCode] 032. Longest Valid Parentheses (Hard) (C++)
指数:[LeetCode] Leetcode 指标解释 (C++/Java/Python/Sql) Github: https://github.com/illuz/leetcode 032. Lon ...
随机推荐
- <NET CLR via c# 第4版>笔记 第8章 方法
8.1 实例构造器和类(引用类型) 构造引用类型的对象时,在调用类型的实例构造器之前,为对象分配的内存总是先被归零 .没有被构造器显式重写的所有字段都保证获得 0 或 null 值. 构造器不能被继承 ...
- tensorflow中 tf.reduce_mean函数
tf.reduce_mean 函数用于计算张量tensor沿着指定的数轴(tensor的某一维度)上的的平均值,主要用作降维或者计算tensor(图像)的平均值. reduce_mean(input_ ...
- 记一次git fatal: Unable to find remote helper for 'https'问题的解决
登陆到远程linux服务器上,使用git, clone的时候报“fatal: Unable to find remote helper for 'https'”错,没管,绕过,使用git clone ...
- IDEA 使用generator逆向工程生成pojo,mapper
1.新建立一个MAVEN项目 2.在pom.xml增加配置 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns: ...
- 0302 IT行业就业与软件工程
阅读以下文章 http://www.thea.cn/news/terminal/9/9389.html http://www.shzhidao.cn/system/2015/09/22/0102610 ...
- ambassador 学习八 流量拷贝说明
这个功能nginx 的mirror 插件也支持,基本原理就是数据发送后端,但是不进行响应 参考图 实现方式 原始请求 getambassador.io/config: | --- apiVersion ...
- ZedGraph右键菜单怎样禁止它弹出(转)
private void ZGC_ContextMenuBuilder( ZedGraphControl sender, ContextMenuStrip me ...
- 判断网络类(获取mac) InternetCheck
using System; using System.Collections.Generic; using System.Net.NetworkInformation; using System.Ru ...
- Web验证方式(1)--Http Basic Authentication
Http Basic Authentication是HTTP协议中定义的Web系统中的验证方式.参考wiki 主要的实现机制如下: 1. 用户通过浏览器匿名访问web资源. 2. web服务器检测到w ...
- windows 如何查看端口占用进程ID 进程名称 强制结束进程
1.查看指定端口的占用情况C:\>netstat -aon|findstr "9050" 协议 本地地址 外部地址 ...