给定一个包含符号{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.
我们能有更好的解决方案吗?
答案 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]应该由我们自己初始化。