以下是https://community.topcoder.com/stat?c=problem_statement&pm=14635所述问题的代码。它通过静态变量countPossible跟踪可能的交错(如给出的问题描述中所述)。
public class InterleavingParentheses{
public static int countPossible = 0;
public static Set<String> dpyes = new HashSet<>(); //used for dp
public static Set<String> dpno = new HashSet<>(); //used for dp
public static void numInterleaves(char[] s1, char[] s2, int size1, int size2){
char[] result = new char[size1+size2];
numInterleavesHelper(result,s1,s2,size1,size2,0,0,0);
}
public static void numInterleavesHelper(char[] res, char[] s1, char[] s2, int size1, int size2, int pos, int start1, int start2){
if (pos == size1+size2){
if (dpyes.contains(new String(res))){
countPossible+=1;
}
else{
if(dpno.contains(new String(res))){
countPossible+=0;
}
else if (isValid(res)){
dpyes.add(new String(res));
countPossible+=1;
}
else{
dpno.add(new String(res));
}
}
}
if (start1 < size1){
res[pos] = s1[start1];
numInterleavesHelper(res,s1,s2,size1,size2,pos+1,start1+1,start2);
}
if (start2 < size2){
res[pos] = s2[start2];
numInterleavesHelper(res,s1,s2,size1,size2,pos+1,start1,start2+1);
}
}
private static boolean isValid(char[] string){
//basically checking to see if parens are balanced
LinkedList<Character> myStack = new LinkedList<>();
for (int i=0; i<string.length; i++){
if (string[i] == "(".charAt(0)){
myStack.push(string[i]);
}
else{
if (myStack.isEmpty()){
return false;
}
if (string[i] == ")".charAt(0)){
myStack.pop();
}
}
}
return myStack.isEmpty();
}
}
我使用scanner类放入输入字符串s1 =“()()()()()()()()()()()()()()()()( )()()()“和s2 =”()()()()()()()()()()()()()()()()()“进入这个函数虽然由于考虑了重复的交错,HashSet的使用大大降低了时间,但是大输入字符串仍然占用了大量时间。输入字符串的大小应该最多为2500个字符,而我的代码不适用于长字符串。如何修改它以使其更好?
答案 0 :(得分:0)
您的dp设置仅在最后使用,因此最多可以保存O(n)
,但您已经完成了许多O(n)
操作以达到该点,因此算法完整性与相同。要使dp生效,您需要将O(2^n)
操作减少到O(n^2)
。
由于其中一个测试用程序的答案为487,340,184,因此对于您的程序来说,要生成此答案,需要调用numInterleavesHelper
的次数,因为每次调用只能将countPossible
增加1。要求答案“模10 ^ 9 + 7”的问题表明预期会有大量答案。
这排除了创建每个可能的结果字符串,大多数字符串操作以及一次计数1个字符串之类的事情。即使你对它进行了优化,那么单独的迭代次数也会让它变得不可行。
相反,请考虑具有大约10,000,000次迭代的算法。每个字符串的长度为2500.这些约束是故意选择的,因此2500 * 2500符合此迭代次数,这表明2D dp解决方案。
如果您创建一个数组:
int ways[2501][2501] = new int[2501][2501];
然后你想要的答案是:
ways[2500][2500]
此处ways[x][y]
是创建有效字符串的方式数,其中从第一个字符串中取出x
个字符,并从第二个字符串中取出y
个字符。每次添加一个角色时,你都有两个选择,从第一个字符串开始,或从第二个字符串开始。新的方式是以前的方式的总和,所以:
ways[x][y] = ways[x-1][y] + ways[x][y-1]
您还需要检查每个字符串是否有效。如果每次添加一个字符,它们都是有效的,开始数量减去结束数量的数量是0或更大,最后这个数字是0。可以预先计算s1
和s2
的每个前缀中每种类型的parens数量,以便对其进行定时检查。