简体   繁体   中英

C# implementation- “Print all combinations of balanced parentheses”

I implemented polygenelubricants's java code ( Valid Permutation of Parenthesis ) in C#.

My C# Code:

public static void CombiParentheses(int open, int close, StringBuilder str)
{
    if (open == 0 && close == 0)
    {
        Console.WriteLine(str.ToString());
        str.Clear();
    }
    if (open > 0) //when you open a new parentheses, then you have to close one parentheses to balance it out.
    {                
        CombiParentheses(open - 1, close + 1, str.Append("{"));
    }
    if (close > 0)
    {                
        CombiParentheses(open , close - 1, str.Append("}"));
    }
}

However I'm getting the wrong result:

CombiParentheses(3, 0, tempString2);
{{{}}}
}{}}
}{}
}{{}}
}{}

What causes this difference between C# and Java implementation?

The issue is not in the Java->C# translation, but in the fact that you translated a string to a StringBuilder. When you call

str.Append("(");

You are appending "(" to the current string builder instance ( str ), and when you do

CombiParentheses(open - 1, close + 1, str.Append("("));

passing that instance itself on your method call, not a new instance.

An easy way to see the problem: suppose you're calling

CombiParentheses(2, 0, str);

When the second output string is written, the call stack will have been

CombiParentheses(2, 0, str):
    CombiParentheses(1, 1, str.Append("(")):
        CombiParentheses(0, 2, str.Append("(")):
            CombiParentheses(0, 1, str.Append(")")):
                CombiParentheses(0, 0, str.Append(")")); // StringBuilder was reset here!
        CombiParentheses(1, 0, str.Append(")")):
            CombiParentheses(0, 1, str.Append("(")):
                CombiParentheses(0, 0, str.Append(")"));

Since you're using a single string builder instance, and you cleared it right before the call stack went into

CombiParentheses(1, 0, str.Append(")"));

The next output will match the output of that call, as if str had no characters on it yet , not the output you're expecting (which would be as if str still had a "(" on it).

If you used a string instead, when you do (string + ")") , the result is a new string, not the same object that you modified, so the problem doesn't arise, when you get back to a CombiParentheses call made earlier in the recursive execution you still have the original string that CombiParentheses call received.

You can use this do see it in runtime:

public static void CombiParentheses(int open, int close, StringBuilder str)
{
    Console.WriteLine("open: {0}; close: {1}; str: {2}", open, close, str.ToString());
    if (open == 0 && close == 0)
    {
        Console.WriteLine(str.ToString());
        str.Clear();
    }

    if (open > 0)
    {
        CombiParentheses(open - 1, close + 1, str.Append("("));
    }

    if (close > 0)
    {
        CombiParentheses(open, close - 1, str.Append(")"));
    }
}

public static void CombiParenthesesFixed(int open, int close, string str)
{
    Console.WriteLine("open: {0}; close: {1}; str: {2}", open, close, str);
    if (open == 0 && close == 0)
    {
        Console.WriteLine(str);
    }

    if (open > 0)
    {
        CombiParentheses(open - 1, close + 1, str + "(");
    }

    if (close > 0)
    {
        CombiParentheses(open, close - 1, str + ")");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM