一个合法的括号匹配序列被定义为:
1. 空串""是合法的括号序列
2. 如果"X"和"Y"是合法的序列,那么"XY"也是一个合法的括号序列
3. 如果"X"是一个合法的序列,那么"(X)"也是一个合法的括号序列
4. 每个合法的括号序列都可以由上面的规则生成
例如"", "()", "()()()", "(()())", "(((()))"都是合法的。
从一个字符串S中移除零个或者多个字符得到的序列称为S的子序列。
例如"abcde"的子序列有"abe","","abcde"等。
定义LCS(S,T)为字符串S和字符串T最长公共子序列的长度,即一个最长的序列W既是S的子序列也是T的子序列的长度。
小易给出一个合法的括号匹配序列s,小易希望你能找出具有以下特征的括号序列t:
1、t跟s不同,但是长度相同
2、t也是一个合法的括号匹配序列
3、LCS(s, t)是满足上述两个条件的t中最大的
因为这样的t可能存在多个,小易需要你计算出满足条件的t有多少个。
如样例所示: s = "(())()",跟字符串s长度相同的合法括号匹配序列有:
"()(())", "((()))", "()()()", "(()())",其中LCS( "(())()", "()(())" )为4,其他三个都为5,所以输出3.
题目分析:
题目有点长,得仔细读清楚。比如这里的子序列定义为S中移除零个或者多个字符得到的序列,并不是s中连续的字符组成的。。
首先要观察到,两个合法括号序列的LCS最大为s-1。所以就不用再找出最大长度了,因为找出最大长度工作量很大。
这题我自己的做法是先求出了所有的符合1,2的括号序列。再找出LCS是s-1的。超时
这题先满足第三个条件最重要。。
求所有括号序列时,先确定有多少对括号n,根据n-1对括号的结果构建当前所有序列。对上一个结果中所有序列进行左加"()",右加"()",和"(" ")"操作。因为前面左加和右加可能会出现重复,所以想到用set存上一个的结果。但是因为还是遍历上一个结果并且删除,然后存入新的,set不合适,想到用队列,每遍历有个就是删除一个了。
package com.xiaojiang.sort; import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc=new Scanner(System.in); while(sc.hasNext()){ String s=sc.nextLine(); int n=s.length()/2; LinkedList<String> q=new LinkedList<>(); //队列 q.add("()"); int count=0;
// for(int i=2;i<=n;i++){ int size=q.size(); for(int j=0;j<size;j++){ String str=q.poll(); q.add(str+"()"); if(!q.contains("()"+str))//去除重复的结果。 q.add("()"+str); q.add("("+str+")"); } } q.remove(s); for(String ss:q){ if(isLCS(s,ss)) count++; } System.out.println(count); } } public static boolean isLCS(String s,String t){ for(int i=0;i<s.length();i++){ for(int j=0;j<t.length();j++){ if((s.substring(0,i)+s.substring(i+1)).equals(t.substring(0,j)+t.substring(j+1))) { return true; } } } return false; } }
因为题目不需要计算出所有括号序列,所以上面方法很明显不是好方法。
首先我们要知道最大LCS是|s|-1。我们只要遍历原始字符串s,去除其中一个字符,将该字符插入到剩下字符串的每个位置,如果插入后的新字符串合法(是匹配括号字符串序列),那表明找到一个符合要求的。添加到set中,set存的是LCS为|s|-1的序列。
最后的结果要 - 1 ,因为插入的位置会和删除的位置相同,就是原始字符串了。
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc=new Scanner(System.in); while(sc.hasNext()){ String s=sc.nextLine(); char[] c=s.toCharArray(); HashSet<String> set=new HashSet<>(); for(int i=0;i<s.length();i++){ char e=c[i]; String b1=s.substring(0,i)+s.substring(i+1); for(int j=0;j<s.length();j++){ String b2=b1.substring(0,j)+e+b1.substring(j); if(isLegal(b2)) set.add(b2); } } System.out.println(set.size()-1); } } public static boolean isLegal(String s){ Stack<Character> stack=new Stack<>(); if(s.charAt(0)==')') return false; stack.push('('); for(int i=1;i<s.length();i++){ if(stack.isEmpty()){ if(s.charAt(i)=='(') stack.push('('); else return false; }else{ if(s.charAt(i)=='(') stack.push('c'); else{ char c=stack.pop(); if(c==')') return false; } } } return stack.isEmpty(); } }