301 - Remove invalid parentheses

Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.

Note: The input string may contain letters other than the parentheses ( and ).

Examples: "()())()" -> ["()()()", "(())()"] "(a)())()" -> ["(a)()()", "(a())()"] ")(" -> [""]

先思考一道简单一些的,如果去掉minimum这个限制,返回一个修改后valid的,要怎么做? 我的思路是用一个counter,遇到做括号就+1,右括号就-1,invalid的情况有如下两种: 1) 遇到右括号的时候,没有左括号可以pop,namely counter is zero 2) 最后stack里面还剩左括号没有pop, namely counter is larger than zero 第一种情况skip掉这种右括号,第二种情况append counter个右括号 如果要求minimum remove,并返回一个结果呢?这就比较tricky了, O(n)时间复杂度的算法是从左到右扫一遍,再从右到左扫一遍,用一个counter,删掉遇到的不合法的‘右’括号,这样我们就尽可能保留了左括号,从而保证minimum删除操作。

//)(())(
    public String oneValid(String s){
        int counter = 0;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if (c == '('){
                counter++;
            }
            if (c == ')'){
                counter--;
                if (counter < 0){
                    counter = 0;
                    continue;
                }
            }
            sb.append(c);
        }
        counter = 0;
        //(())(
        s = sb.toString();
        sb = new StringBuilder();
        for (int i = s.length() - 1; i >= 0; i--){
            char c = s.charAt(i);
            if (c == '('){
                counter--;
                if (counter < 0){
                    counter = 0;
                    continue;
                }
            }
            if (c == ')'){
                counter++;
            }
            sb.append(c);
        }
        return sb.reverse().toString();
    }

再进一步,如果要返回所有valid的结果呢? 我觉得应该是用backtracking Now, we back to our original problem which aims to find the valid expression with minimum removals. Treat this as a graph. Each node on graph represents the current state after modification on its parent node. Then this problem is transformed to getting shortest path(s) on a graph. Obviously, BFS is the right track. Note, we should avoid duplicate state like we usually have a visited array to mark the nodes we explored. Same here, otherwise, the program will get TLE.

public List<String> minimum(String s){
  if (s == null) return new ArrayList<String>();
  Queue<String> Q = new LinkedList<String>();
  Set<String> set = new HashSet<>();
  List<String> res = new ArrayList<>();
  set.add(s);
  Q.offer(s);
  boolean found = false;//must be defined out of the while loop
  while (!Q.isEmpty()){
    int size = Q.size();
    for (int i = 0; i < size; i++){
      String tmp = Q.poll();      
      if (isValid(tmp)){
        res.add(tmp);
        found = true;
      }
      for (int j = 0; j < tmp.length(); j++){
        if (found) break;
         char e = tmp.charAt(j);
         StringBuilder sb = new StringBuilder(tmp);
         if (e == '(' || e == ')'){
           sb.deleteCharAt(j);
         }
         if (!set.contains(sb.toString())){           
           set.add(sb.toString());
           Q.offer(sb.toString());
         }
      }
    }
    if (found) return res;
  }
  return res;
}

private boolean isValid(String s){
  int counter = 0;
  for (int i = 0; i < s.length(); i++){
    char c = s.charAt(i);
    if (c == '('){
      counter++;
    }
    if (c == ')'){
      counter--;
    }
    if (counter < 0) return false;
  }
  return counter == 0;
}

results matching ""

    No results matching ""