I am reading the Algorithm Design Manual Second Edition and this is from an exercise question. Quoting the question
A common problem for comp
C# 7 or so now also has tuples. You don't need the out
argument anymore.
As many others pointed out, there is no need for a stack or a queue or alike.
Just a balance counter suffices.
-- Checks the balance of braces in a string.
-- Error case 1: More closes than open. We can identify the first culprit by index.
-- Error case 2: More opens than closes. We return the length of the String,
-- indicating that there are closed braces missing.
-- Good case: As many opens as closes. We return (True,Nothing)
checkBraces :: String -> (Bool,Maybe Int)
checkBraces [] = (True,Nothing)
checkBraces s =
let (balance,offender) = foldl account (0,-1) $ zip [0..] s in
if balance == 0
then (True,Nothing)
else (False,Just $ if -1 == offender then length s else offender)
where
account :: (Int,Int) -> (Int, Char) -> (Int,Int)
account acc@(_,off) _ | off /= -1 = acc -- Once there was an error we stop looking what happens.
account acc@(b,off) (i,'(') = (b+1,off) -- One more open brace.
account (b,off) (i,')') -- One more closed brace.
| b <= 0 = (b-1,i) -- Ouch. We closed more than we opened!
| otherwise = (b-1,off) -- Okay.
account acc (i,_) = acc -- Some other character (Not in ['(',')'])
testCases =
[ ("",True)
, ("(",False)
, (")",False)
, ("))((",False)
, ("()()",True)
, ("(()))",False)
]
test =
all ((==) True) . fmap testOne $ testCases
where
testOne (tc,expected) =
let (actual,_) = checkBraces tc in
actual == expected
Side note: The syntax highlighting for Haskell here needs some improvement, right? :)
Remove all non-'(' and -')' characters from an input string. This gives you a string of '(' and ')' only.
If the string has odd length, return false.
Else, start reading along our string, adding +1 to a "signature" for each '(' and -1 for each ')'; if this signature is ever negative, return false.
Return true.
Piggy back on @Russell's idea:
public class BalancedBrackets
{
private readonly char[] _leftBrackets = new char[] {'[', '(', '{', '<'};
private readonly char[] _rightBrackets = new char[] {']', ')', '}', '>'};
public bool IsBalanced(string input)
{
int count = 0;
foreach (var character in input.ToCharArray())
{
if (_leftBrackets.Contains(character)) count++;
if (_rightBrackets.Contains(character)) count--;
}
return count == 0;
}
}
Time order O(n) and spatial order O(1)
public static bool IsBalanced(string input)
{
int count = 0;
for (int i = 0; i < input.Length; i++)
{
if (input[i] == '(') count++;
if (input[i] == ')') count--;
if (count < 0) return false;
}
if (count == 0) return true;
return false;
}
using System;
class Solution
{
public int solution(string S)
{
int x1 = 0;
int x2 = 0;
for (int i = 0; i < S.Length; i++)
{
if (S[i] == ')')
if (x1 <= 0) return 0;
else x1--;
else if (S[i] == '(')
x1++;
}
if (x1 == 0)
return 1;
else
return 0;
}
}
Here's a one liner for C# using System.Linq:
expression.Aggregate(0, (state, ch) => state == -1 ? -1 : state + (ch == '(' ? 1 : ch == ')' ? -1 : 0)) == 0
it utilizes the fact that string is in fact IEnumerable of chars so we can run Aggregate function on it. We increase the counter by 1 when we encounter the '(' char and decrease it by 1 on ')' char. Once we reach the negative value of -1 we stay there to indicate the invalid state.
It doesn't have any early exit implemented so it will be slower than most implementations presented here but maybe someone will find it useful :)