【问题标题】:counting boolean parenthesizations implementation计算布尔括号实现
【发布时间】:2011-10-05 19:40:49
【问题描述】:

给定一个包含符号 {true, false, and, or, xor} 的布尔表达式,计算为表达式加上括号以使其计算结果为 true 的次数。

例如,只有 1 种方法可以将“真假异或真”括起来,使其计算结果为真。

这是我的算法

we can calculate the total number of parenthesization of a string
Definition:  
N - the total number of 
True -  the number of parenthesizations that evaluates to true
False - the number of parenthesizations that evaluates to false
True + False = N 
Left_True - the number of parenthesization in the left part that evaluates to True
same to Left_False, Right_True, Right_False

we iterate the input string from left to right and deal with each operator as follows:


if it is "and", the number of parenthesization leads to true is
    Left_True * Right_True;

if it is "xor", the number of parenthesization leads to true
    Left_True * Right_False + Left_False * Right_True

if it is 'or', the number is
    N - Left_False * Right_False 

Here is my psuedocode 

n = number of operator within the String 

int[n][n] M; // save number of ways evaluate to true

for l = 2 to n
for i = 1 to n-l+1
  do j = i+l-1  
  // here we have different string varying from 2 to n starting from i and ending at j
  for k = i to j-1
  // (i,k-1) is left part
  // (k+1, j) is right part
  switch(k){
    case 'and':  // calculate, update array m
    case 'or':  // same
    case 'xor':
  }

  we save all the solutions to subproblems and read them when we meet them again. thus save time.

我们能有更好的解决方案吗?

【问题讨论】:

  • “我们能有更好的解决方案”是什么意思?假设您要一个:请定义“更好”。您是否正在寻找一种更快的解决方案,一种使用更少的代码,更少的内存使用......此外,您可能想进一步澄清您的伪代码,我曾经很难弄清楚它应该如何工作(它可能如果您写下开关内部发生的事情,请提供帮助
  • 我正在寻找更快的解决方案和更少的代码实现。比如计算括号的方式很繁琐,括号导致真假
  • 我很困惑——(true and false) xor truetrue and (false xor true) 都评估为真。
  • @ben 如果操作顺序是从左到右,那么“真假异或真”也是一种解决方案
  • 我也很困惑:if it is 'or', the number is N - Left_False * Right_False。我有一种感觉,除了 N 之外,还有更多的括号

标签: algorithm implementation dynamic-programming


【解决方案1】:

你的伪代码给出了一个 O(2^n) 的算法。我认为你可以在 O(n^3) 中找到一些东西。


首先,让我们看看您的算法的复杂性。假设检查括号所需的操作数是T(n)。如果我理解得很好,您的算法包括:

  • 将表达式分成两部分(n-1 种可能性)

  • 检查左右部分是否有适当的括号。

所以T(n) = checking if you cut at the first place + checking if you cut at the second place + ... + checking if you cut at the last place

T(n) = T(1)+T(n-1) + T(2)+T(n-2) + ... + T(n-1)+T(1) + n

稍微计算一下就会告诉你T(n) = 2^n*T(1) + O(n^2) = O(2^n)


我的想法是,您只需要检查括号是否为“子词”。 “subword_i_j”由位置 i 和位置 j 之间的所有文字组成。当然i<j 所以你有N*(N-1)/2 子词。假设L[i][j] 是 subword_i_j 的有效括号数。为方便起见,我将忘记其他值 M[i][j] 指出导致错误的括号数,但不要忘记它在这里!

您想要计算所有可能的子词,从最小的(大小 1)到最大的(大小 N)。

您首先为所有 i 计算 L[i][i]。有 N 个这样的值。这很简单,如果第 i 个字数为 True,则 L[i][i]=1 否则 L[i][i]=0。现在,您知道所有大小为 1 的子词的括号数。

假设您知道所有大小为 S 的子词的括号。

然后计算L[i][i+S] for i 在 1 和 N-S 之间。这些是大小为 S+1 的子字。它包括以所有可能的方式(S 方式)拆分子词,检查左侧部分(大小为 S1和右侧是否部分(大小为 S2和之间的运算符(或、异或和)是兼容的。有 S*(N-S) 个这样的值。

最后,你会得到L[1][N],它会告诉你是否有一个有效的括号。

费用是:

checking subwords of size 1 + checking subwords of size 2 + ... + checking subwords of size N

= N + N-1 + 2*(N-2) + 2*(N-2) + .. + (N-1)*(1)

= O(N^3)


复杂性更好的原因是在您的伪代码中,您多次检查相同的子词而不将结果存储在内存中。

编辑:Arglllll,我忽略了句子we save all the solutions to subproblems and read them when we meet them again. thus save time.。好吧,似乎如果你这样做了,你也有一个最坏情况 O(N^3) 的算法。不要以为你能做得比这更好......

【讨论】:

    【解决方案2】:

    这个问题可以通过Dynamic-Algorithm解决,类似于矩阵链乘问题,详细答案如下:

    1、设运算由操作数a_i和操作符b_j组成(1

    2、令DPone[i][j]为{a_i b_i a_i+1 ... b_j-1 b_j}中括号的次数,使得结果为1,令DPzero[i][j]是在 {a_i b_i a_i+1 ... b_j-1 b_j} 中加括号的方法数,使得结果为 0

    3、构建函数oper(i,j,k),返回值是当b_k是{a_i b_i a_i+1 ... b_j-1中最后使用的运算符时,运算结果为1的次数b_j},直接操作方法是基于b_k。比如b_i是and,所以返回值为DPone[i][k]*DPone[k+1][j]。

    4、DP方程如下:

    DPone[i][j] = max{ sum ( oper(i,j,k) ) i

    所以我们只需要确定 DPone[1][n]。复杂度为 O(n^3)

    意图:

    1、确定DPone[i][j]之后再确定DPzero[i][j],其实很简单,DPzero[i][j]=total_Parenthesize_Ways[i][j]-DPone[i][ j]

    2、查找DPone的顺序是[1][1],[2][2],...[n][n],[1][2],[2][3],。 ..[n-1][n],[1][3],[2][4]......[2][n],[1][n],当然是[1] [1]~[n][n]应该自己初始化。

    【讨论】:

      【解决方案3】:

      这是计算布尔值和运算符数组的括号的代码。

      时间复杂度O(N^3)和空间复杂度O(N^2)

      public static int CountingBooleanParenthesizations(bool[] boolValues, string[] operators)
      {
          int[,] trueTable = new int[boolValues.Length, boolValues.Length];
          int[,] falseTable = new int[boolValues.Length, boolValues.Length];
          for (int j = 0; j < boolValues.Length; j++)
          {
              for (int i = j; i >= 0; i--)
              {
                  if (i == j)
                  {
                      trueTable[i, j] = boolValues[i] ? 1 : 0;
                      falseTable[i, j] = boolValues[i] ? 0 : 1;
                  }
                  else
                  {
                      int trueSum = 0;
                      int falseSum = 0;
                      for (int k = i; k < j; k++)
                      {
                          int total1 = trueTable[i, k] + falseTable[i, k];
                          int total2 = trueTable[k + 1, j] + falseTable[k + 1, j];
                          switch (operators[k])
                          {
                              case "or":
                                  {
                                      int or = falseTable[i, k] * falseTable[k + 1, j];
                                      falseSum += or;
                                      or = total1 * total2 - or;
                                      trueSum += or;
                                  }
                                  break;
                              case "and":
                                  {
                                      int and = trueTable[i, k] * trueTable[k + 1, j];
                                      trueSum += and;
                                      and = total1 * total2 - and;
                                      falseSum += and;
                                  }
                                  break;
                              case "xor":
                                  {
                                      int xor = trueTable[i, k] * falseTable[k + 1, j] + falseTable[i, k] * trueTable[k + 1, j];
                                      trueSum += xor;
                                      xor = total1 * total2 - xor;
                                      falseSum += xor;
                                  }
                                  break;
                          }
                      }
                      trueTable[i, j] = trueSum;
                      falseTable[i, j] = falseSum;
                  }
              }
          }
           return trueTable[0, boolValues.Length - 1];
      }
      

      【讨论】:

        猜你喜欢
        • 2017-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-28
        • 2011-01-08
        • 1970-01-01
        • 2016-12-21
        • 1970-01-01
        相关资源
        最近更新 更多