<p>Given a string <font face="monospace">s</font> of <code>&#39;(&#39;</code> , <code>&#39;)&#39;</code> and lowercase English characters.</p>

<p>Your task is to remove the minimum number of parentheses ( <code>&#39;(&#39;</code> or <code>&#39;)&#39;</code>, in any positions ) so that the resulting <em>parentheses string</em> is valid and return <strong>any</strong> valid string.</p>

<p>Formally, a <em>parentheses string</em> is valid if and only if:</p>

<ul>
	<li>It is the empty string, contains only lowercase characters, or</li>
	<li>It can be written as <code>AB</code> (<code>A</code> concatenated with <code>B</code>), where <code>A</code> and <code>B</code> are valid strings, or</li>
	<li>It can be written as <code>(A)</code>, where <code>A</code> is a valid string.</li>
</ul>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;lee(t(c)o)de)&quot;
<strong>Output:</strong> &quot;lee(t(c)o)de&quot;
<strong>Explanation:</strong> &quot;lee(t(co)de)&quot; , &quot;lee(t(c)ode)&quot; would also be accepted.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;a)b(c)d&quot;
<strong>Output:</strong> &quot;ab(c)d&quot;
</pre>

<p><strong class="example">Example 3:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;))((&quot;
<strong>Output:</strong> &quot;&quot;
<strong>Explanation:</strong> An empty string is also valid.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= s.length &lt;= 10<sup>5</sup></code></li>
	<li><code>s[i]</code> is either&nbsp;<code>&#39;(&#39;</code> , <code>&#39;)&#39;</code>, or lowercase English letter.</li>
</ul>

class Solution:
    def minRemoveToMakeValid(self, s: str) -> str:
        # solution 1. stack. time: O(n) space: O(n). 
        # intuition: doesn't need to care about letters. they don't matter. find unnecssary brackets using stack.
        # stack = []
        # for i, char in enumerate(s):
        #     if char == "(":
        #         stack.append((i, char))
        #     elif char == ")":
        #         if stack and stack[-1][1] == "(":
        #             stack.pop()
        #         else:
        #             stack.append((i, char))
        
        # if not stack: # if there's no parentheses to remove
        #     return s

        # p = 0 # pointer to stack
        # ans = [] # add characters in s except the ones to be removed
        # for i in range(len(s)):
        #     if p >= len(stack) or i < stack[p][0]:
        #         ans.append(s[i])
        #     elif i == stack[p][0]:
        #         p += 1
        
        # return "".join(ans)

        # solution 2. Approach 2. Time: O(n) space: O(n)
        # build answer string as iterating over the input string 
        # first pass to remove ")"
        # second pass to remove "("
        # def buildString(s, open, close):
        #     stack = []
        #     num_open = 0
        #     for i in range(len(s)):
        #         if s[i] not in "()":
        #             stack.append(s[i])
        #         elif s[i] == open:
        #             stack.append(s[i])
        #             num_open += 1
        #         else:
        #             if num_open > 0:
        #                 stack.append(s[i])
        #                 num_open -= 1
        #     return "".join(stack)
        
        # s = buildString(s, "(", ")")
        # s = buildString(s[::-1], ")", "(")
        # return s[::-1]

        
        # solution 3. Approach 3. time: O(n) space: o(n) optimized more than approach 2. no stack used.
        # In the first iteration of s, remove invalid ")" and keep track of balance. If balance > 0 after the iteration,
        # it is guaranteed that invalid "(" are the rightmost ones.
        first_pass_chars = [] 
        balance = 0
        open_seen = 0
        for c in s:
            if c == "(":
                open_seen += 1
                balance += 1
            elif c == ")":
                if balance == 0:
                    continue
                balance -= 1
            first_pass_chars.append(c)
        
        result = []
        valid_open_brackets = open_seen - balance
        for c in first_pass_chars:
            if c == "(":
                if valid_open_brackets == 0:
                    continue
                valid_open_brackets -= 1
            result.append(c)
        return ''.join(result)
        
        



19100