反向括号 - Codefights

ReverseParentheses - Codefights

我很难用 JavaScript

解决这个问题

给你一个由英文字母、标点符号、空白字符和括号组成的字符串s。保证s中的括号组成正则括号序列

你的任务是反转每对匹配括号中的字符串,从最里面的那个开始。

示例

对于字符串 s = a(bc)de 输出应该是

reverseParentheses(s) = "acbde".

Input/Output

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

由英文字母、标点符号、空白字符和括号组成的字符串。保证括号组成正则括号序列

限制条件:

5 ≤ x.length ≤ 55.

[输出] 字符串

它必须使用以下输入:

  1. s: a(bcdefghijkl(mno)p)q 预期输出: apmnolkjihgfedcbq
  2. s: co(de(fight)s) 预期输出: cosfighted
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)
}
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

解决方法如下:

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;
};
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();
}

给定一个大小为 n 的字符串,这是一个用 C 编写的递归代码,其运行时间复杂度为 O(n)。 代码背后的想法是从字符串的开头开始,每次遇到左括号时,切换到右括号并向后打印,然后在右括号后完成打印。 请注意,当您向后打印时,左括号“[”被视为右括号,反之亦然用于右括号“]”。 最大字符串大小为 100 万,如果需要处理更长的字符串,请更改数组大小。

#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;
}

这是我没有使用正则表达式的JS解决方案,对于初学者来说可能更容易理解。注释使代码 self-explanatory 但想法是找到最后一个左括号(如果表达式有嵌套括号),然后找到匹配的右括号,反转里面的文本并保留 运行函数直到字符串不再有左括号(根据问题的定义,不再有右括号)。

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;
}

这是一个使用正则表达式的递归解决方案,当正则表达式中有匹配项时调用 reverseString 方法,该匹配项使用替换函数来替换反向字符串。一旦被逆转,它就会再次循环,直到没有更多的匹配项..

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);   
}

对于Python 3(不确定Python 2),此代码有效。这确实假设(如 Code Fights 上的问题所述)每个括号都是一对括号的一部分。

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 
def reverseParentheses(s)
  0 while s.gsub!(/\(([^()]*)\)/) { .reverse }
  return s
end

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

在 JS 中

使用正则表达式

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;
}

简单方法:-

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;
}

在Python中:

简单方法

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

使用堆栈方法

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)

在 C++ 中

简单方法:-

reverseString 函数将使用交换方法反转字符串,而 reverseParentheses 函数将递归更新字符串。

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;
}

在Java中: 简单方法

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;
}

在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;
}

在Javascript/nodejs

//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('')));

}

这是一个很好的直截了当的 c++ 答案

每当我们看到左括号时,我们就将索引压入堆栈,当我们找到右括号时,我们弹出最后一个索引并反转这两个索引之间的子字符串。然后我们删除额外的括号

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;
  
  

}


这是 Vahan 答案的修改版本,将正则表达式执行压缩为一个替换调用:

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

我的做法是找到配对括号,将括号中的顺序倒过来。最后,使用 filter() 删除所有括号。与其他解决方案相比,该解决方案有点冗长,但我发现我可以更好地遵循这种方法。

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++];
  }
};
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;
}

我无法理解 python 最佳解决方案,所以我不得不将其分成几块来理解。

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]+"') + '"'))

输出:

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

这是我通过的解决方案:

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;
}

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

发现此解决方案非常清晰易用