最长有效括号
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”
dp{i}表示0~i的有效括号子串的长度。
遇到’(‘直接跳过,因为之前没有与之匹配的括号。
遇到’)’,我们则开始进行讨论,j=i-1-dp[i-1] (我们需要跳过在这之前的已经匹配的有效子串) 例如: (()()) pos=6,j=1 dp[i-1]=4.
若j处的括号是’(‘,那么状态转移方程为:dp{i}=dp{i-1}]+2;
我们还需要加j-1之前的有效子串。例如: () (()())
class Solution {
public int longestValidParentheses(String s) {
if(s.equals("")){
return 0;
}
int ans=0;
int len=s.length();
int[] dp=new int[len];
dp[0]=0;
for(int i=1;i<len;++i){
if(s.charAt(i)==')'){
int j=i-1-dp[i-1];
if(j>=0&&s.charAt(j)=='('){
dp[i]=dp[i-1]+2;
if(j-1>=0){
dp[i]+=dp[j-1];
}
}
}
ans=Math.max(ans,dp[i]);
}
return ans;
}
}
最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
O(logn)做法:利用lower_bound
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length==0){
return 0;
}
int total=0;
int[] vec=new int[nums.length];
vec[total++]=nums[0];
for(int i=0;i<nums.length;++i){
if(nums[i]>vec[total-1]){
vec[total++]=nums[i];
}else {
vec[lower_bound(vec,total,nums[i])]=nums[i];
}
}
return total;
}
public int lower_bound(int[] arr,int k,int target){
int l=0;
int r=k;
while (l<r){
int mid=l+(r-l)/2;
if(arr[mid]>=target){
r=mid;
}else{
l=mid+1;
}
}
return l;
}
}
10. 正则表达式匹配
给定一个字符串 (s) 和一个字符模式 (p)。实现支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符。
‘*’ 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s) ,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 1:
输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p = “a*”
输出: true
解释: ‘*’ 代表可匹配零个或多个前面的元素, 即可以匹配 ‘a’ 。因此, 重复 ‘a’ 一次, 字符串可变为 “aa”。
示例 3:
输入:
s = “ab”
p = “.*”
输出: true
解释: “.” 表示可匹配零个或多个(‘‘)任意字符(‘.’)。
示例 4:
输入:
s = “aab”
p = “c*a*b”
输出: true
解释: ‘c’ 可以不被重复, ‘a’ 可以被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入:
s = “mississippi”
p = “mis*is*p*.”
输出: false
这道题我们需要分情况讨论,首先先注意一点 前一定是有字母的,例如 a就表示a可以为0个也可以为n个。
我们就要分清理讨论了。
首先dp{i,j}表示s串前i个与p串前j个字符的匹配情况。
如果si==pj的话,dp{i,j}=dp{i-1,j-1}
如果pj==’.’的话,dp{i,j}=dp{i-1,j-1},同上。
接下来就要讨论pj==’*’的情况了。
- 1.s[i]!=p[j-1]&&p[j-1]!=’.’,即ab a* 这种情况,那么我就要舍弃a*这一部分,即a的个数为0,那么dp{i,j}=dp{i,j-2}.
- 2.分类讨论(以下若有一项匹配成功那么说明s串匹配是true)
- 当出现 bab,b.这种情况时,那么我们就要舍弃 . 这种情况,那么dp{i,j}=dp{i,j-2},即舍弃这一部分。
- 当出现aaa a* 这种情况,dp{i,j}=dp{i-1,j},这种就类似s串删除了一个a字符(这样子*就可以匹配多个a)
- dp{i,j}=dp{i,j-1},例如 aabc a*bc 这种情况就像p串把 *变成了a,这样子就只匹配一个字符a.
至于初始化,dp[0][0]表示我们两个串还没开始匹配,那么肯定为true
class Solution {
public boolean isMatch(String s, String p) {
if(s==null||p==null){
return false;
}
int n=s.length();
int m=p.length();
boolean[][] dp=new boolean[n+1][m+1];
dp[0][0]=true;
for(int i=1;i<m;++i){
if(p.charAt(i)=='*'&&dp[0][i-1]){
dp[0][i+1]=true;
}
}
//这部分表示我们匹配串的多个开始位置 我们需要把他们都找出来。
//因为不止dp[0][0]是开始的位置 例如c*a 我们是可以舍弃c*(使用0个c)从a开始的,
//并不一定是从c开始,即dp[0][2]=true 具体的话自己思考一下就知道了
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if (s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='.'){
dp[i][j]=dp[i-1][j-1];
}
if(p.charAt(j-1)=='*'){
if(p.charAt(j-2)!=s.charAt(i-1)&&p.charAt(j-2)!='.'){
dp[i][j]=dp[i][j-2];
}else{
dp[i][j]=dp[i-1][j]||dp[i][j-1]||dp[i][j-2];
}
}
}
}
return dp[n][m];
}
}
44. 通配符匹配
给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 ‘?’ 和 ‘*’ 的通配符匹配。
‘?’ 可以匹配任何单个字符。
‘*’ 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
示例 1:
输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p = “*”
输出: true
解释: ‘*’ 可以匹配任意字符串。
示例 3:
输入:
s = “cb”
p = “?a”
输出: false
解释: ‘?’ 可以匹配 ‘c’, 但第二个 ‘a’ 无法匹配 ‘b’。
示例 4:
输入:
s = “adceb”
p = “*a*b”
输出: true
解释: 第一个 ‘’ 可以匹配空字符串, 第二个 ‘’ 可以匹配字符串 “dce”.
示例 5:
输入:
s = “acdcb”
p = “a*c?b”
输入: false
这道题比上一道更加直观,讨论的情况也少很多。
首先dp{i,j}表示s串前i个与p串前j个字符的匹配情况。
如果si==pj的话,dp{i,j}=dp{i-1,j-1}
如果pj=='.'的话,dp{i,j}=dp{i-1,j-1},同上。
接下来就要讨论pj=='*'的情况了。这一步是和上面一样的。
当pj=='*'的时候,其实很直观,*只有为空串或者匹配n个字符,而且多个字符是从s串第i个到第i+n-1个这个范围,
不可能是这个范围之外的串了,自己推一下就知道了。
匹配多个字符,就和上一题一样,dp{i,j}=dp{i-1,j},就是s串删除一个字符,只是上一题删除的重复的字符,
这一题删除的是不重复的多个字符。
接着是空串,即dp{i,j}=dp{i,j-1},即把*删掉,还有就是匹配一个字符,也是dp{i,j}=dp{i,j-1}.
那么转移方程就是dp{i,j}=dp{i-1,j}||dp{i,j-1}.其中一种成立即为true.
记得初始化化,即dp[0][0]不一定是开始的点,例如: ???? ?是可以为空串的。可以从dp[0][1]开始,
也可以从dp[0][2]开始,以此类推。
class Solution {
public boolean isMatch(String s, String p) {
if(s==null||p==null){
return false;
}
int n=s.length();
int m=p.length();
boolean[][] dp=new boolean[n+1][m+1];
dp[0][0]=true;
for(int i=1;i<=m;++i){
if(p.charAt(i-1)=='*'&&dp[0][i-1]){
dp[0][i]=true;
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='?'){
dp[i][j]=dp[i-1][j-1];
}
if(p.charAt(j-1)=='*'){
dp[i][j]=dp[i][j-1]||dp[i-1][j];
}
}
}
return dp[n][m];
}
}