241. Different Ways to Add Parentheses
MediumView on LeetCode
Advertisement
Intuition
Each operator divides the expression into a left and right sub-expression. Recursively compute all possible results from each sub-expression, then combine every left result with every right result using the operator. Memoize on the sub-string to avoid recomputation.
Algorithm
- 1For each operator (+, -, *) at position i: left = DiffWays(expr[0..i-1]), right = DiffWays(expr[i+1..]).
- 2Combine every l in left with every r in right using the operator. Collect all results.
- 3If no operator found, the expression is a number - return [int.Parse(expression)].
Example Walkthrough
Input: "2-1-1"
- 1.Split at first "-": left=[2], right=DiffWays("1-1")=[0,2]. Combine: 2-0=2, 2-2=0.
- 2.Split at second "-": left=DiffWays("2-1")=[1], right=[1]. Combine: 1-1=0... wait, 1-1=0 already counted.
- 3.Results: [0, 2].
Output: [0, 2]
Common Pitfalls
- •Always return a copy list from the memo - not a reference - if using memoization.
241.cs
C#
// Approach: Divide and conquer — split the expression at each operator.
// For each operator at position i, recursively compute all results from the left sub-expression
// and all results from the right sub-expression, then combine them with that operator.
// Memoize by expression string to avoid recomputing the same sub-expression multiple times.
// Base case: if the expression contains no operator, it is a single number.
// The total number of results equals the Catalan number for the number of operators.
// Time: O(n x Catalan(n)) Space: O(n x Catalan(n)) for the memo cache.
public class Solution
{
// Cache to store already computed results for expressions.
private static Dictionary<string, List<int>> memoizationCache = new Dictionary<string, List<int>>();
public IList<int> DiffWaysToCompute(string expression)
{
return ComputeAllPossibleResults(expression);
}
// Recursive function to compute all possible results from the input expression.
private List<int> ComputeAllPossibleResults(string expression)
{
// Check if the result for this expression is cached.
if (memoizationCache.ContainsKey(expression))
return memoizationCache[expression];
List<int> results = new List<int>();
// Base case: if expression is a single number, return it as the only result.
if (!expression.Contains("+") && !expression.Contains("-") && !expression.Contains("*"))
{
results.Add(int.Parse(expression));
return results;
}
// Iterate through each character of the expression string.
for (int i = 0; i < expression.Length; i++)
{
char operation = expression[i];
// When an operator is found, divide the expression into two parts.
if (operation == '-' || operation == '+' || operation == '*')
{
List<int> resultsLeft = ComputeAllPossibleResults(expression.Substring(0, i));
List<int> resultsRight = ComputeAllPossibleResults(expression.Substring(i + 1));
// Compute all combinations of results from left and right sub-expressions.
foreach (int leftResult in resultsLeft)
{
foreach (int rightResult in resultsRight)
{
if (operation == '-')
results.Add(leftResult - rightResult);
else if (operation == '+')
results.Add(leftResult + rightResult);
else if (operation == '*')
results.Add(leftResult * rightResult);
}
}
}
}
// Cache the computed results for the current expression.
memoizationCache[expression] = results;
// Return all the computed results.
return results;
}
}Advertisement
Was this solution helpful?