'ReverseParentheses - Codefights

I'm having a really tough time solving this problem with JavaScript

You are given a string s that consists of English letters, punctuation marks, whitespace characters and brackets. It is guaranteed that the brackets in s form a regular bracket sequence.

Your task is to reverse the strings in each pair of matching parenthesis, starting from the innermost one.

Example

For string s = a(bc)de the output should be

reverseParentheses(s) = "acbde".

Input/Output

[time limit] 4000ms (js)
[input] string s

A string consisting of English letters, punctuation marks, whitespace characters and brackets. It is guaranteed that parenthesis form a regular bracket sequence.

Constraints:

5 ≤ x.length ≤ 55.

[output] string

It has to work with the following inputs:

  1. s: a(bcdefghijkl(mno)p)q Expected Output: apmnolkjihgfedcbq
  2. s: co(de(fight)s) Expected Output: cosfighted


Solution 1:[1]

function reverseParentheses(s) {
    if (s.includes('(')){
        return reverseParentheses(reverseOnce(s));
    } else {     
        return s;
    }
}

function reverseOnce(s){
    var regexp = /\(([^()]*)\)/i;
    var subStr = regexp.exec(s)[1];
    subStr = subStr.split('').reverse().join('');
    return s.replace(regexp, subStr)
}

Solution 2:[2]

In JS

Using Regex

function reverseInParentheses(s) {
    if (s.match(/\([a-z]*\)/)) {
        return reverseInParentheses(s.replace(/\([a-z]*\)/, 
            Array.from(s.match(/\([a-z]*\)/)[0].replace(/\(|\)/g,'')).reverse().join('')));
    }
    else return s;
}

Simple Method:-

function reverseInParentheses(s) {
    while (true) {
        let c = s.indexOf(")");    
        if (c === -1) break;
        let o = s.substring(0, c).lastIndexOf("(");
        let start = s.substring(0, o);
        let middle = s.substring(o + 1, c).split("").reverse().join("");
        let end = s.substring(c + 1, s.length);
        s = start + middle + end;
    }
    return s;
}

In Python:

Simple Method

def reverseInParentheses(s):
    return eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')

Using Stacks Method

def reverseInParentheses(s):
    stack = []
    for x in s:
        if x == ")":
            tmp = ""
            while stack[-1] != "(":
                tmp += stack.pop()
            stack.pop() # pop the (
            for item in tmp:
                stack.append(item)
        else:
            stack.append(x)

    return "".join(stack)

In C++

Simple Method:-

reverseString function will reverse the String using the swapping method while reverseParentheses function will update string recursively.

string reverseString(string s){
    for(int i = 0;i < s.length()/2;i++){
        char t = s[s.length()-1-i];
        s[s.length()-1-i] = s[i];
        s[i] = t;
    }
    return s;
}
string reverseInParentheses(string s) {
    int beg = 0;
    int end = s.length() - 1;
    for(int i = 0; i < s.length(); i++){
        if(s[i] == '(')
            beg = i;
        if(s[i] == ')'){
            end = i;
            string temp = s.substr(beg + 1, end - beg - 1);
            return reverseInParentheses(s.substr(0, beg) + reverseString(temp) + s.substr(end + 1));
         }
    }
    return s;
}

Solution 3:[3]

def reverseParentheses(s):
    for i in range(len(s)):
        if s[i] == "(":
            start = i
            print (s[:start])
        if s[i] == ")":
            end = i
            print (end)
            return reverseParentheses(s[:start] + s[start+1:end][::-1] + s[end+1:])
    return s

Solution 4:[4]

Here is a solution:

const reverse = (str) => str.split('').reverse().join('');

const reverseParentheses = (s) => {
    while (s.includes('(')) {
        var l = s.lastIndexOf('(');
        var r = s.indexOf(')', s.lastIndexOf('('));
        s = s.slice(0, l) + reverse(s.slice(l + 1, r)) + (r + 1 === s.length ? s.slice(r, -1) : s.slice(r + 1));
    }
    return s;
};

Solution 5:[5]

Here is a modified version of Vahan's answer, condensing the regex execution into only one replace call:

function reverseInParentheses(inputString) {
    regex = /\(([^()]*)\)/i;
    
    if (inputString.includes('(')) {
        return reverseInParentheses(inputString.replace(regex, (_, $1) => $1.split('').reverse().join('')));   
    } else {
        return inputString
    }
}

Solution 6:[6]

Given a string of size n, here's a recursion code written in C which runs in O(n) time complexity. The idea behind the code is to start with the beginning of the string and every time you encounter an opening bracket, you switch to its closing bracket and print backwards then complete printing after that closing brackets. Note that when you are printing backwards, opening brackets '[' are considered closing brackets and vise versa for closing brackets ']'. Maximum string size is 1 million, change array sizes if you need to process longer strings.

#include <stdio.h>
#include <string.h>
int n, other[1000010], stt[1000010];
char st[1000010];

void rec(int i, int dir) {
    if(i >= n) return;
    if(st[i] == '[') {
        if(dir == 1) { // going right with '[' means opening
            rec(other[i]-1, -dir); // go to the closing bracket and change direction
            rec(other[i]+1, dir); // continue after the closing bracket after finishing
        }
        return;
    }

    if(st[i] == ']') {
        if(dir == -1) { // going left with ']' means opening
            rec(other[i]+1, -dir); // go to the closing bracket and change direction
            rec(other[i]-1, dir); // continue after the closing bracket after finishing
        }
        return;
    }
    putchar(st[i]); // print character
    rec(i+dir, dir); // continue same direction
}

int main() {
    scanf("%s", st);
    n = strlen(st);
    for(int i=0, j, k=0; i<n; ++i) {
        if(st[i] == '[') stt[k++] = i;
        else if(st[i] == ']')  {
            j = stt[--k];
            other[i] = j, other[j] = i;
        }
    }
    rec(0, 1); // start from 0, with direction 1 (right)
    return 0;
}

Solution 7:[7]

Here's my JS solution without using regular expressions, it might be more understandable for a beginner. The comments make the code self-explanatory but the idea is to find the last opening bracket (in case the expression has nested brackets), and then find the matching closing bracket, reverse the text inside and keep running the function until the string doesn't have any more opening brackets (and by the definition of the problem, no more closing brackets).

function reverseParentheses(s) {
    // We keep running the function while 
    // there's an opening bracket in the string
    while (s.indexOf("(") !== -1) {
        s = reverseP(s);
    }
    return s;
}

function reverseP(s) {
    let len = s.length;
    // We find the innermost/last opening bracket,
    // and then we're going to find the matching closing bracket,
    // which is the next closing bracket after the opening bracket
    let openBracketInd = s.lastIndexOf("(");
    
    // The characters before the opening bracket
    let beforeBracket = s.slice(0, openBracketInd+1);
    
    // The characters before the opening bracket
    let afterBracket = s.slice(openBracketInd+1, len);
    
    // To get the index of the closing bracket we add the 
    // characters before the bracket to the index of the first closing
    // bracket in the string after the opening bracket
    let closeBracketInd = beforeBracket.length + afterBracket.indexOf(")");
    
    // Once we have the indexes, we're going to slice the string 
    // to remove the brackets
    let firstPart = s.slice(0, openBracketInd);
    let secondPart = s.slice(closeBracketInd+1, len);
    let middle = s.slice(openBracketInd+1, closeBracketInd);
    
    // We reverse the string between the brackets
    middle = middle.split('').reverse().join('');
    
    // And finally we join the parts and return the string
    return firstPart+middle+secondPart;
}

Solution 8:[8]

This is a recursive solution using regular expressions, there is a reverseString method that get called when there is a match in the regular expression, this match uses the replace function in order to replace the reveresed string. once is reversed it does the cycle again until there are no more matches..

function reverseParentheses(s) {
    const reverseString = str => (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
    const regex = /(\([\w\s\[\]!\.\,\;\:\?]*\))/g;
    const iterator = a => {
        if(regex.test(a)){
            a=a.replace(regex, full => reverseString(full.replace(/[()]/g,'')));    
            return iterator(a);
        } else  return a;
    }
    return iterator(s);   
}

Solution 9:[9]

For Python 3 (not sure about Python 2), this code works. This does assume (as the problem on Code Fights states) that each parenthesis is a part of a pair.

def reverseParentheses(s):
    from collections import Counter
    for i in range(Counter(s)['(']):
        one = s.rsplit('(',1)
        two = one[1].split(')',1)
        s = one[0]+two[0].replace(two[0],two[0][::-1]+two[1])
        print(s)
    return s 

Solution 10:[10]

def reverseParentheses(s)
  0 while s.gsub!(/\(([^()]*)\)/) { $1.reverse }
  return s
end

Solution 11:[11]

A solution in F#:

let foldi fold first source =
    source
    |> List.fold (fun (prev,i) c -> (fold i prev c,i + 1)) (first,0)
    |> fst

let reverseParentheses (s: string) =
    let go pos (stack: list<list<char>>) (c: char) : list<list<char>> =
        let fail () = failwithf "Parse error at pos %d, char '%c'." pos c
        match c with
        | '(' -> [] :: stack
        | ')' ->
            match stack with
            | top :: next :: rest -> ((List.rev top @ next) :: rest)
            | _ -> fail ()
        | _ ->
            match stack with
            | top :: rest -> ((c :: top) :: rest)
            | _ -> fail ()
    s |> Seq.toList |> foldi go [[]] |> List.head |> List.rev |> List.toArray |> String

Solution 12:[12]

In Java: Simple Method

String reverseInParentheses(String inputString) {

    StringBuilder str = new StringBuilder();
    int start = 0;
    int end = inputString.length() - 1;
    str.setLength(0);
    if (inputString.contains("(")) {
        start = inputString.lastIndexOf("(");
        end = inputString.indexOf(")", start);
        str.append(inputString, start+1, end);
        return reverseInParentheses(inputString.substring(0, start) + str.reverse().toString() + inputString.substring(end+1));
    }
    return inputString;
}

Solution 13:[13]

In Javascript

function reverseInParentheses(inputString) {
    let mainArr = inputString.split('');
    let arrLength = mainArr.length;
    let arr1 = [];
    for(let i = 0; i < arrLength; i++) {
        if(mainArr[i] != ')') {
            arr1.push(mainArr[i]);
        } else {
            let temp = reverseSelectedString(arr1); // call function to reverse selected string
            arr1 = arr1.splice(0, arr1.lastIndexOf("("));
            arr1 = arr1.concat(temp);
        }
    }
    return arr1.join('');
}

function reverseSelectedString(arrFirst) {
    let arr2 = [];
    let arrLength = arrFirst.length;
    for(let j = arrLength; j >= 0; j--) {
        if(arrFirst[j] != '(') {
            arr2.push(arrFirst[j]);
        } else {
            break;
        }
    }
    return arr2;
}

Solution 14:[14]

In Javascript/node js

//Regex for opening and closing parenthesis
const o_brc = /[\{\[\(]/g;
const c_brc= /[\}\]\)]/g;

const revPar = str => {
  let top =-1;
  let rev_str = [];

  for(let i in str){
    if(c_brc.test(str[i])){

        const rev = [];
        let j = i-1;
        while(rev_str.length){
          if(o_brc.test(rev_str[top])){
            break;
          }
          rev.push( rev_str.pop());
          top--;
        }

        rev_str.pop(); //pop out the opening brackets after reversing
        top--;
        rev_str = [...rev_str, ...rev]; 
        top += rev.length; //increment the top upto rev.length
    }
    else{
      rev_str.push(str[i]); //push to rev_str if not a closing bracket
      top++;
    }
  }

  console.log((rev_str.join('')));

}

Solution 15:[15]

this is a nice straight forward answer in c++

whenever we see open parentheses we push the index into the stack, and when we find a closing one, we pop the last index and reverse the substring between those two indises. then we remove the additional parentheses

string reverseInParentheses(string inputString) {
    
    
  stack<int> index;
   
  for (int i = 0 ; i < inputString.length(); i++){
      if (inputString[i] == '('){
          index.push(i);
      }
      if (inputString[i] == ')'){
          reverse(inputString.begin()+ index.top(), inputString.begin()+i+1);
          index.pop();
      }
    }
    string s = "";
    for (int i = 0; i < inputString.length();i++){
        if (inputString[i] != '(' && inputString[i] != ')'  )
            s += inputString[i];
    }
    
    cout << s << endl;
    return s;
  
  

}


Solution 16:[16]

My approach is to find the pairing parentheses, reverse the sequence in the parenthesis. At the end, use filter() to remove all the parentheses. The solution is a little bit wordy compare to other solutions, but I find that I can follow up this approach better.

function reverseInParentheses(inputString) {
  const stack = [];
  let inputList = inputString.split("");

  for (let i = 0; i < inputList.length; i++) {
    if (inputList[i] === "(") {
      stack.push(i);
    } else if (inputList[i] === ")") {
      const begin = stack.pop();
      const reversedSeq = reverseString(inputList.slice(begin + 1, i));
      appendSubsequence(reversedSeq, inputList, begin + 1);
    }
  }

  return inputList.filter((char) => char !== "(" && char !== ")").join("");
}

const reverseString = (sequence) => {
  for (let i = 0; i < sequence.length / 2; i++) {
    const endIndex = sequence.length - i - 1;
    [sequence[i], sequence[endIndex]] = [sequence[endIndex], sequence[i]];
  }
  return sequence;
};

const appendSubsequence = (sequence, arr, begin) => {
  let counter = 0;

  while (counter < sequence.length) {
    arr[begin++] = sequence[counter++];
  }
};

Solution 17:[17]

Simple and easy with DEQUEUE

String reverseInParentheses(String s) {
    Deque dq = new LinkedList<Character>();
    for(int i=0;i<s.length();i++){
        dq.add(s.charAt(i));
        if(s.charAt(i)==')'){
            int k=i-1;
            String temp="";
            dq.removeLast();
            char c1=(char)dq.getLast();
            while(c1!='('){
                temp=temp+dq.removeLast().toString();
                c1=(char)dq.getLast();
            }
            dq.removeLast();
            int c=0;
            while(c<temp.length()){
                dq.add(temp.charAt(c));
                c++;
            }
        }
    }
    String temp="";
    Iterator iteratorVals = dq.iterator();
      
    while (iteratorVals.hasNext()) {
        temp=temp+iteratorVals.next();
    }
    return temp;
}

Solution 18:[18]

i couldnt understand the python top solution so I had to break it in chunks to understand.

In Python:

Simple Method

def reverseInParentheses(s):
    return eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')





s = "abc(def(ghi)klm)nop"
print("original",s)
print("first replace", s.replace('(', '"+("'))
print("second replace", s.replace('(', '"+("').replace(')', '")[::-1]+"'))
print("third step addition",'"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')
print('final evaluation', eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"'))

output:

original abc(def(ghi)klm)nop

first replace abc"+("def"+("ghi)klm)nop

second replace abc"+("def"+("ghi")[::-1]+"klm")[::-1]+"nop

third step addition "abc"+("def"+("ghi")[::-1]+"klm")[::-1]+"nop"

final abcmlkghifednop

Solution 19:[19]

Here is my solution that passed:

function extractParenthesesAndKey(input) {
  const match = input.match(/\(([^()]*)\)/i);
  if (!match) return null;
  const result = match[0];
  const key = result.substring(1, result.length - 1);
  return { result, key };
}

function hasParentheses(string) {
    return string.includes('(') || string.includes(')');
}

function solution(inputString) {
    let interpolatedInput = inputString.slice(); // no side-effect
    let itHasParentheses = hasParentheses(interpolatedInput);
    while(itHasParentheses) {
        const extractedData = extractParenthesesAndKey(interpolatedInput);
        interpolatedInput = interpolatedInput.replace(extractedData.result, 
        extractedData.key
          .split('')
          .reverse()
          .join(''));
        solution(interpolatedInput);
        itHasParentheses = hasParentheses(interpolatedInput);
    }
    return interpolatedInput;
}

Solution 20:[20]

function solution(inputString) {
    while(inputString.includes('(')){
      inputString =  inputString.replaceAll(/\([a-z]*\)/g, str=>str.split('').slice(1, -1).reverse().join(''));
    }
    return inputString
}

Have found this solution much clear and ease

Solution 21:[21]

public static String reverseParentheses(String s) {
    StringBuilder sb = new StringBuilder();
    char[] sArray = s.toCharArray();
    int[] firstIndex = new int[s.length()]; //??'('???
    int[] lastIndex = new int[s.length()]; //??')'???
    int num = 0; // ????')'?????
    int count = 0; // ????"("?????
    boolean flag = false; //???????
    int index; //')'??'('???
    int countParentheses; //')'???'('????????
    for (int i = 0; i < sArray.length; i++) {
        if (sArray[i] == '(') {
            //?????
            if (count == num && count != 0) {
                flag = true;
            } else if (count - num > 1 && num != 0) {//?????
                flag = true;
            }
            firstIndex[count] = i;
            count++;
            continue;

        } else if (sArray[i] == ')') {
            System.out.println("??->??')'?" + sb);
            lastIndex[num] = i;
            if (flag) {
                index = count - num;
                countParentheses = count + num;
                flag = false;
            } else {
                //?????
                index = count - num - 1;
                countParentheses = count - num;

            }
            System.out.println("??????:" + (firstIndex[index] - (countParentheses) + 1));
            String s1 = sb.substring(firstIndex[index] - (countParentheses) + 1, lastIndex[num] - num - count);
            System.out.println("???????????" + s1);
            StringBuilder getString = new StringBuilder();
            getString.append(s1);
            getString.reverse();//??
            System.out.println("???????" + (firstIndex[index] - (countParentheses) + 1));
            System.out.println("??????:" + (lastIndex[num] - count - num));
            System.out.println("??????" + getString.toString().length());
            sb.replace(firstIndex[index] - (countParentheses) + 1, lastIndex[num] - count - num,
                    getString.toString().trim());
            System.out.println("????" + sb);
            num++;
            continue;

        } else if (sArray[i] == ')' && count == num) {

        } else {
            sb.append(sArray[i]);
        }
    }

    System.out.println("...." + sb);
    return sb.toString();
}