Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jianminchen/1a09cc4b3c2607df137bf5e002f4bd4e to your computer and use it in GitHub Desktop.
Save jianminchen/1a09cc4b3c2607df137bf5e002f4bd4e to your computer and use it in GitHub Desktop.
Leetcode 301 - remove invalide paratheses - readable function name
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace removeInvalidParatheses
{
/// <summary>
/// Leetcode 301 - remove invalid paratheses
///
/// </summary>
class Program
{
static void Main(string[] args)
{
RunTestcase1();
RunTestcase2();
RunTestcase3();
}
// test case 1: "()())()" -> ["()()()", "(())()"]
public static void RunTestcase1()
{
var results = removeInvalidParentheses("()())()");
}
// test case 2: "(a)())()" -> ["(a)()()", "(a())()"]
public static void RunTestcase2()
{
var results = removeInvalidParentheses("(a)())()");
}
// test case 3: ")(" -> [""]
public static void RunTestcase3()
{
var results = removeInvalidParentheses(")(");
}
/// <summary>
/// code review on August 2, 2017
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static List<String> removeInvalidParentheses(String s) {
var invalid = countInvalidParatheses(s);
var maxRemovalLeft = invalid[0];
var maxRemovalRight = invalid[1];
var deDuplicate = new HashSet<string>();
FindAllValidCandidates(s, 0, deDuplicate, new StringBuilder(), maxRemovalLeft, maxRemovalRight, 0);
return new List<String>(deDuplicate);
}
/// <summary>
/// count how many invalid open and close paratheses
/// by scanning the string from left to right once
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private static int[] countInvalidParatheses(string s)
{
var maxRemovalLeft = 0;
var maxRemovalRight = 0;
var length = s.Length;
// preprocess the string to get maximum number of
// invalid left and right paratheses
for (int i = 0; i < length; i++)
{
var visit = s[i];
bool isOpen = visit == '(';
bool isClose = visit == ')';
if (isOpen)
{
maxRemovalLeft++;
}
else if (isClose)
{
if (maxRemovalLeft != 0)
{
maxRemovalLeft--;
}
else
{
maxRemovalRight++;
}
}
}
return new int[] { maxRemovalLeft, maxRemovalRight };
}
/// <summary>
/// code review on August 2, 2017
/// this algorithm will do brute force
/// DFS search, 2^n choice.
/// argument: matchChecking
/// make sure that the parathese is correct to match
/// "()",
/// if "(" is used, then matchChecking should increment one first
/// and then visit ")",
/// if ")" is used, then decrement one and then is equal to zero.
/// ")(",
/// if ")" is used, then matchChecking decrease one for ")", < 0, return false
///
/// Find all valid candidates, remove minimum invalid paratheses.
/// Using StringBuilder to set the length, the backtracking is very easy to write.
/// </summary>
/// <param name="s"></param>
/// <param name="index"></param>
/// <param name="deDuplicate"></param>
/// <param name="candidate"></param>
/// <param name="maxRemovalLeft"></param>
/// <param name="maxRemovalRight"></param>
/// <param name="matchChecking"></param>
public static void FindAllValidCandidates(
String s,
int index,
HashSet<String> deDuplicate,
StringBuilder candidate,
int maxRemovalLeft,
int maxRemovalRight,
int matchChecking)
{
if (maxRemovalLeft < 0 || maxRemovalRight < 0 || matchChecking < 0)
{
return;
}
int length = s.Length;
bool finishScan = index == length;
// base case
if (finishScan)
{
if (maxRemovalLeft == 0 && maxRemovalRight == 0 && matchChecking == 0)
{
deDuplicate.Add(candidate.ToString());
}
return;
}
var visit = s[index];
var current = candidate.Length;
bool isOpen = visit == '(';
bool isClose = visit == ')';
if (isOpen)
{
// not use (, remove '('
FindAllValidCandidates(s, index + 1, deDuplicate, candidate, maxRemovalLeft - 1, maxRemovalRight, matchChecking);
// use (
FindAllValidCandidates(s, index + 1, deDuplicate, candidate.Append(visit), maxRemovalLeft, maxRemovalRight, matchChecking + 1);
}
else if (isClose)
{
// not use )
FindAllValidCandidates(s, index + 1, deDuplicate, candidate, maxRemovalLeft, maxRemovalRight - 1, matchChecking);
// use )
FindAllValidCandidates(s, index + 1, deDuplicate, candidate.Append(visit), maxRemovalLeft, maxRemovalRight, matchChecking - 1);
}
else
{
FindAllValidCandidates(s, index + 1, deDuplicate, candidate.Append(visit), maxRemovalLeft, maxRemovalRight, matchChecking);
}
// backtracking - remove the last char
candidate.Length = current;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment