动态编程方法 - 交织括号

时间:2017-11-25 07:22:38

标签: java algorithm performance dynamic-programming

以下是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个字符,而我的代码不适用于长字符串。如何修改它以使其更好?

1 个答案:

答案 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。可以预先计算s1s2的每个前缀中每种类型的parens数量,以便对其进行定时检查。