【问题标题】:Algorithm to get all the possible combinations of operations from a given numbers从给定数字中获取所有可能的操作组合的算法
【发布时间】:2020-01-06 11:36:25
【问题描述】:

我想写一个给定一组数字的函数,例如: 2、3

它返回所有带有+、-、*和/的操作组合。

这两个数字的结果是:

2+3   
2-3  
2*3  
2/3 

对于数字: 2、3、4 应该是:

(2+3)+4   
(2+3)-4  
(2+3)*4  
(2+3)/4

(2-3)+4  
(2-3)-4  
(2-3)*4  
(2-3)/4  

...

2+(3+4)
2+(3*4)
2+(3-4)
2+(3/4)

...

3+(2+4)
3+(2*4)
3+(2-4)
3+(2/4)

...
and so on

运算符的顺序无关紧要,重点是从所有可能的运算组合中获得所有结果。

【问题讨论】:

  • 可能是2+(3*4)3+(2*4),还是数字总是按顺序排列,运算符总是从左到右应用?
  • @JosephSible-ReinstateMonica 是的,有可能,我会添加更多示例,以免引起误解
  • 您的所有示例仍然按顺序排列数字。
  • @JosephSible-ReinstateMonica 我意识到了这一点,并在 30 秒后更新了它,完成了!
  • 你可以枚举所有可能有n个叶子的二叉树,然后枚举所有可能的节点和叶子的设置。

标签: algorithm recursion math


【解决方案1】:

我将通过使用Reverse Polish Notation 来解决这个问题,您可以在其中将运算符和操作数附加到字符串,同时考虑一些简单的规则。

例如,表达式2 + (3 * 4) 在逆波兰表示法中将是2 3 4 * +。另一方面,(2 + 3) * 4 将是 2 3 + 4 *

如果我们已经有一个部分表达式,我们可以添加一个操作数或一个运算符。

添加一个操作数总是可以完成的,它将堆栈的大小增加 1。另一方面,添加一个运算符会将堆栈的大小减少 1(删除两个最顶部的操作数并添加结果)因此只有在堆栈至少有两个条目时才能完成。最后,要形成一个有效的表达式,堆栈大小必须正好为 1。

这激发了具有以下接口的递归函数:

getSubexpressions(remainingOperands, currentStackSize)

该函数返回一个子表达式列表,这些子表达式可以附加到堆栈大小为currentStackSize 并使用操作数remainingOperands 的部分表达式。​​

这个递归函数的基本情况是没有剩余操作数并且堆栈大小为 1:

if remainingOperands = ∅ and currentStackSize = 1
    return { "" }

在这种情况下,我们只能将空字符串添加到表达式中。

在所有其他情况下,我们需要收集一组子表达式

subexpressions = { }   // initialize an empty set

如果我们可以添加一个运算符,我们可以简单地附加它:

if currentStackSize >= 2
    for each possible operator o
        subexpressions.add(o + getSubexpressions(remainingOperands, currentStackSize - 1))

符号o + getSubexpressions(remainingOperands, currentStackSize - 1) 是连接操作数o 与调用getSubexpressions() 返回的所有子表达式的简写。

我们快到了。最后剩下的一点是添加潜在的操作数:

for each o in remainingOperands
    subexpressions.add(o + getSubexpressions(remainingOperands \ { o }, currentStackSize + 1))

符号remainingOperands \ { o } 代表集差,即没有o 的剩余操作数集。

就是这样。全文:

getSubexpressions(remainingOperands, currentStackSize)
    if remainingOperands = ∅ and currentStackSize = 1
        return { "" }

    subexpressions = { }   // initialize an empty set

    if currentStackSize >= 2
        for each possible operator o
            subexpressions.add(o + getSubexpressions(remainingOperands, currentStackSize - 1))

    for each o in remainingOperands
        subexpressions.add(o + getSubexpressions(remainingOperands \ { o }, currentStackSize + 1))

    return subexpressions

这个递归调用通常会有重叠的子调用。因此,您可以使用 memoization 来缓存中间结果,而不是一遍又一遍地重新计算它们。

这是 C# 中没有记忆的概念验证实现。特别是可以使用更合适的数据结构更有效地设计操作数管理:

static void Main(string[] args)
{
    foreach (var expr in GetSubexpressions(new List<string> { "1", "2", "3" }, 0, new StringBuilder()))
    {
        Console.WriteLine(expr);
    }
}

static char[] operators = { '+', '-', '*', '/' };

static IEnumerable<StringBuilder> GetSubexpressions(IList<string> remainingOperands, int currentStackSize, StringBuilder sb)
{
    if (remainingOperands.Count() == 0 && currentStackSize == 1)
    {
        yield return sb;
        yield break;
    }

    if(currentStackSize >= 2)
    {
        foreach (var o in operators)
        {
            sb.Append(o);
            foreach (var expr in GetSubexpressions(remainingOperands, currentStackSize - 1, sb))
                yield return expr;
            sb.Remove(sb.Length - 1, 1);
        }
    }

    for (int i = 0; i < remainingOperands.Count; ++i)
    {
        var operand = remainingOperands[i];
        remainingOperands.RemoveAt(i);
        sb.Append(operand);
        foreach (var expr in GetSubexpressions(remainingOperands, currentStackSize + 1, sb))
            yield return expr;
        sb.Remove(sb.Length - operand.Length, operand.Length);
        remainingOperands.Insert(i, operand);
    }
} 

程序打印以下输出:

12+3+
12-3+
12*3+
12/3+
12+3-
12-3-
12*3-
12/3-
12+3*
12-3*
12*3*
12/3*
12+3/
12-3/
12*3/
12/3/
123++
123-+
123*+
123/+
123+-
123--
123*-
123/-
123+*
123-*
123**
123/*
123+/
123-/
123*/
123//
13+2+
13-2+
13*2+
13/2+
13+2-
13-2-
13*2-
13/2-
13+2*
13-2*
13*2*
13/2*
13+2/
13-2/
13*2/
13/2/
132++
132-+
132*+
132/+
132+-
132--
132*-
132/-
132+*
132-*
132**
132/*
132+/
132-/
132*/
132//
21+3+
21-3+
21*3+
21/3+
21+3-
21-3-
21*3-
21/3-
21+3*
21-3*
21*3*
21/3*
21+3/
21-3/
21*3/
21/3/
213++
213-+
213*+
213/+
213+-
213--
213*-
213/-
213+*
213-*
213**
213/*
213+/
213-/
213*/
213//
23+1+
23-1+
23*1+
23/1+
23+1-
23-1-
23*1-
23/1-
23+1*
23-1*
23*1*
23/1*
23+1/
23-1/
23*1/
23/1/
231++
231-+
231*+
231/+
231+-
231--
231*-
231/-
231+*
231-*
231**
231/*
231+/
231-/
231*/
231//
31+2+
31-2+
31*2+
31/2+
31+2-
31-2-
31*2-
31/2-
31+2*
31-2*
31*2*
31/2*
31+2/
31-2/
31*2/
31/2/
312++
312-+
312*+
312/+
312+-
312--
312*-
312/-
312+*
312-*
312**
312/*
312+/
312-/
312*/
312//
32+1+
32-1+
32*1+
32/1+
32+1-
32-1-
32*1-
32/1-
32+1*
32-1*
32*1*
32/1*
32+1/
32-1/
32*1/
32/1/
321++
321-+
321*+
321/+
321+-
321--
321*-
321/-
321+*
321-*
321**
321/*
321+/
321-/
321*/
321//

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    • 2013-03-21
    • 2015-10-07
    • 2023-03-17
    • 1970-01-01
    相关资源
    最近更新 更多