Алгоритм получения всех возможных комбинаций операций с заданными номерами - PullRequest
0 голосов
/ 05 января 2020

Я хочу написать функцию с заданным набором чисел, например: 2, 3

. Возвращает все комбинации операций с +, -, * и /.

* 1004. * Результат для этих двух чисел будет:
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

Порядок операторов не имеет значения смысл в том, чтобы получить все результаты из всех возможных комбинаций операций.

1 Ответ

0 голосов
/ 06 января 2020

Я бы решил эту проблему, используя Reverse Poli sh Обозначение , где вы можете просто добавлять операторы и операнды в строку, учитывая некоторые простые правила.

Например, выражение 2 + (3 * 4) будет иметь значение 2 3 4 * + в обратной записи Poli sh. С другой стороны, (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

Этот рекурсивный вызов обычно будет иметь перекрывающиеся вызовы. Следовательно, вы можете использовать памятку для кэширования промежуточных результатов, а не пересчитывать их снова и снова.

Вот реализация концепции для проверки без памятки в 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//
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...