【问题标题】:How to efficiently distribute a logical expression in javascript如何在 javascript 中有效地分发逻辑表达式
【发布时间】:2023-02-21 22:00:30
【问题描述】:

假设你有这个逻辑表达式

(A or B or C) and (D or E) and (F or G or H)

正如您在这里看到的,我们在括号内有 OR 运算符,在外面有 AND 运算符。我们可以说这个逻辑表达式是 AND(OR) 类型的。

我想将此表达式转换为 OR(AND)。

例子:

(A or B) and (C or D) = (A and C) or (A and D) or (B and C) or (B and D)

实现这个的简单方法(在 javascript 中):

class OrNode<C = string> {
    /* constructor logic */
    nodeType = 'OR';
    children: C[];
}

class AndNode<C = string> {
    /* constructor logic */
    nodeType = 'AND';
    children: C[];
}

function convert(expression: AndNode<OrNode>): OrNode<AndNode> {
    let children: AndNode[] = [{ nodeType: 'AND', children: [] }];
    expression.children.forEach((orNode) => {
        let temp = children;
        children = [];
        orNode.children.forEach((leafNode) => {
            temp.forEach((andNode) => {
                children.push({
                    nodeType: 'AND',
                    children: [...andNode.children, leafNode],
                });
            });
        });
    });
    return new OrNode<AndNode>({ nodeType: 'OR', children });
}

假设我们有这个表达式:

const expression = new AndNode<OrNode>({
    nodeType: 'AND',
    children: [
        { nodeType: 'OR', children: ['A', 'B', 'C'] },
        { nodeType: 'OR', children: ['D', 'E'] },
        { nodeType: 'OR', children: ['F', 'G', 'H'] },
    ]
});

那么如果我们进行转换,新的转换表达式将等于

{
    nodeType: 'OR',
    children: [
        { nodeType: 'AND', children: ['A', 'D', 'F'] },
        { nodeType: 'AND', children: ['A', 'D', 'G'] },
        { nodeType: 'AND', children: ['A', 'D', 'H'] },
        { nodeType: 'AND', children: ['A', 'E', 'F'] },
        { nodeType: 'AND', children: ['A', 'E', 'G'] },
        { nodeType: 'AND', children: ['A', 'E', 'H'] },
    
        { nodeType: 'AND', children: ['B', 'D', 'F'] },
        { nodeType: 'AND', children: ['B', 'D', 'G'] },
        { nodeType: 'AND', children: ['B', 'D', 'H'] },
        { nodeType: 'AND', children: ['B', 'E', 'F'] },
        { nodeType: 'AND', children: ['B', 'E', 'G'] },
        { nodeType: 'AND', children: ['B', 'E', 'H'] },

        { nodeType: 'AND', children: ['C', 'D', 'F'] },
        { nodeType: 'AND', children: ['C', 'D', 'G'] },
        { nodeType: 'AND', children: ['C', 'D', 'H'] },
        { nodeType: 'AND', children: ['C', 'E', 'F'] },
        { nodeType: 'AND', children: ['C', 'E', 'G'] },
        { nodeType: 'AND', children: ['C', 'E', 'H'] },
    ]
}

这个暴力解法的复杂度是O(M^N),M是括号内条件的最高个数,N是括号块的个数。

有没有办法使用另一种算法来降低这种复杂性?

【问题讨论】:

  • 顺便说一句,它有效吗?复杂度是笛卡尔积。
  • 你是说我的蛮力算法?是的,但我发布的代码只是为了展示转换算法的思想。实际代码包含更多细节(守卫、构造函数逻辑等)。这种强力算法导致我们的服务器在处理大型逻辑表达式时频繁重启。
  • 您可以使用 generator 来创建笛卡尔积。也许这有点帮助。
  • 让我想起(a &amp;&amp; b) == !(!a || !b)。转换中的 not 操作可能会有用。
  • @traktor 不幸的是使用 not 操作是不可能的。

标签: javascript algorithm logical-operators


【解决方案1】:

您在“conjunctive normal form”中有一个表达式,您想将其转换为“disjunctive normal form”。

转换总是可能的,但它也解决了 NP-hard 问题,如布尔可满足性,因此没有已知的有效方法来确定结果公式是否为空。

事实上,对于某些输入,得到的公式的大小将呈指数级增长,因此高效转换肯定是不可能的。上面的 DNF 维基百科文章中给出了一个简单的例子:

(A1个或乙1个) 和 (一个2个或乙2个) 和 ... (一个n或乙n)

将在 DNF 中扩展为包含 2n条款。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-03
    • 2023-01-19
    • 1970-01-01
    • 2012-05-10
    • 2019-01-13
    • 2015-03-04
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多