计算布尔括号内的实现

时间:2011-07-15 01:28:33

标签: algorithm implementation dynamic-programming

给定一个包含符号{true,false,和,或xor}的布尔表达式,计算括号表达式的方法数,使其计算结果为true。

例如,只有一种方法可以将'true和false xor true'括起来,使其评估为true。

这是我的算法

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.

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

3 个答案:

答案 0 :(得分: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个时间是真的那么L[i][i]=1否则L[i][i]=0。现在,您知道大小为1的所有子字的括号数。

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

然后在1和N-S之间为i计算L[i][i+S]。这些是大小为S + 1的子字。它包括以所有可能的方式(S方式)分割子字,检查左侧部分(大小为S1&lt; = S的子字)是否正确部分(其大小为S2 <= S)运算符介于其间(或,xor,和)是兼容的。有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)。不要以为你能做得更好......

答案 1 :(得分:1)

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

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

self.navigationController!.navigationBar.backgroundColor = UIColor.clear

答案 2 :(得分:0)

这个问题可以通过动态算法解决,它类似于矩阵链乘法问题,详细解答如下:

1,让操作由操作数a_i和操作符b_j组成(1&lt; = i&lt; = n,1&lt; = j&lt; = n-1 n是操作数的大小),将true替换为1,将false替换为0

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是和,所以返回值是DPone [i] [k] * DPone [k + 1] [j]。

4,现在DP方程如下:

DPone [i] [j] = max {sum(oper(i,j,k))i&lt; = k&lt; = j-1}

所以我们只需要确定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]应该由我们自己初始化。