递归数组连接错误(JavaScript)

递归数组连接错误(JavaScript),javascript,recursion,Javascript,Recursion,任务:给定一个foo(bar)格式的字符串,将括号内的字符串反转 我的解决方案有一个错误,我无法理解其原因 这是我的密码: const inputs = ["foo(bar)", "(bar)", "foo(bar)blim", "foo(foo(bar))blim", "foo(foo(bar)ddas)blim", "foo(foo(b(tu)ar)ddas)blim&quo

任务:给定一个
foo(bar)
格式的字符串,将括号内的字符串反转

我的解决方案有一个错误,我无法理解其原因

这是我的密码:

    const inputs = ["foo(bar)", "(bar)", "foo(bar)blim", "foo(foo(bar))blim", "foo(foo(bar)ddas)blim", "foo(foo(b(tu)ar)ddas)blim"]
const expected = ["foorab", "rab", "foorabblim", "foobaroofblim", "foosaddbaroofblim", "foosaddbutaroofblim"]

function reverseParans(input) {
    firstLeftParans = input.indexOf('(')
    lastRightParans = input.lastIndexOf(')')

    if (firstLeftParans == -1) {
        if (lastRightParans > -1) {
            return ['<MALFORMED>']
        } else {
            return input.reverse()
        }
    } else {
        if (lastRightParans == -1) {
            return ['<MALFORMED>']
        } else {
            left = input.slice(0, firstLeftParans)
            right = input.slice(lastRightParans+1).slice()
            middle = reverseParans(input.slice(firstLeftParans + 1, lastRightParans))
            return [...left, ...middle, ...right].reverse()
        }
    }
}

function process(str) {
    let input = str.split('');
    let firstLeftParans = input.indexOf('(');
    let lastRightParans = input.lastIndexOf(')');

    if (firstLeftParans == -1 && lastRightParans == -1) {
        return input
    } else if ((firstLeftParans > -1 && lastRightParans == -1) || (lastRightParans > -1 && firstLeftParans == -1)) {
        return "<MALFORMED>"
    }
    result = input.slice(0, firstLeftParans).concat(reverseParans(input.slice(firstLeftParans + 1, lastRightParans)), input.slice(lastRightParans + 1))
    return result.join('')
}

我想我在进行递归调用时错误地改变了一个值,但我不确定在哪里。

你搞乱了你的范围,因为你没有声明你的变量是
reversePans
的本地变量。修改后的代码可以工作:

const inputs = ["foo(bar)", "(bar)", "foo(bar)blim", "foo(foo(bar))blim", "foo(foo(bar)ddas)blim", "foo(foo(b(tu)ar)ddas)blim"]
const expected = ["foorab", "rab", "foorabblim", "foobaroofblim", "foosaddbaroofblim", "foosaddbutaroofblim"]

function reverseParans(input) {
    let firstLeftParans = input.indexOf('(')
    let lastRightParans = input.lastIndexOf(')')

    if (firstLeftParans == -1) {
        if (lastRightParans > -1) {
            return ['<MALFORMED>']
        } else {
            return input.reverse()
        }
    } else {
        if (lastRightParans == -1) {
            return ['<MALFORMED>']
        } else {
            let left = input.slice(0, firstLeftParans)
            let right = input.slice(lastRightParans+1).slice()
            let middle = reverseParans(input.slice(firstLeftParans + 1, lastRightParans))
            return [...left, ...middle, ...right].reverse()
        }
    }
}

function process(str) {
    let input = str.split('');
    let firstLeftParans = input.indexOf('(');
    let lastRightParans = input.lastIndexOf(')');

    if (firstLeftParans == -1 && lastRightParans == -1) {
        return input
    } else if ((firstLeftParans > -1 && lastRightParans == -1) || (lastRightParans > -1 && firstLeftParans == -1)) {
        return "<MALFORMED>"
    }
    result = input.slice(0, firstLeftParans).concat(reverseParans(input.slice(firstLeftParans + 1, lastRightParans)), input.slice(lastRightParans + 1))
    return result.join('')
}
const inputs=[“foo(bar)”,“(bar)”,“foo(bar)blim”,“foo(foo(bar))blim”,“foo(foo(bar)ddas)blim”,“foo(foo(b(tu)ar)ddas)blim”]
预期常数=[“foorab”、“rab”、“foorabblim”、“foobaroofblim”、“foosadbaroofblim”、“foosadbaroofblim”、“foosadbutaroofblim”]
功能反转面板(输入){
设firstLeftParans=input.indexOf('('))
设lastRightParans=input.lastIndexOf('))
if(firstLeftParans==-1){
如果(lastRightParans>-1){
返回['']
}否则{
返回input.reverse()
}
}否则{
如果(lastRightParans==-1){
返回['']
}否则{
设left=input.slice(0,firstlefts)
让right=input.slice(lastRightParans+1).slice()
设middle=reversePans(input.slice(firstLeftParans+1,lastRightParans))
返回[…左,…中,…右]。反转()
}
}
}
功能过程(str){
让输入=str.split(“”);
设firstLeftParans=input.indexOf('(');
设lastRightParans=input.lastIndexOf(');
if(firstLeftParans==-1&&lastRightParans==-1){
返回输入
}else if((firstLeftParans>-1&&lastRightParans==-1)| |(lastRightParans>-1&&firstLeftParans=-1)){
返回“”
}
结果=input.slice(0,firstLeftParans).concat(reverseParans(input.slice(firstLeftParans+1,lastRightParans)),input.slice(lastRightParans+1))
返回结果。连接(“”)
}

通过数学归纳法进行递归可以简化程序。下面的编号注释与代码中的编号相对应-

  • 如果未找到左paren或右paren;返回输入字符串,
    s
  • (归纳法)如果只找到一个参数;返回格式错误的字符串结果
  • (归纳)左、右paren均已找到;返回左括号前的字符串部分,加上递归结果,再加上右括号后的字符串部分
  • 功能流程(s=”“)
    {const l=s.indexOf(“(”/“左”)
    常数r=s.lastIndexOf(“)”/“右”
    如果(l==-1&&r===-1)
    返回s//1
    else if(l==-1 | r==-1)
    返回“”//2
    其他的
    返回s.substring(0,l)//3
    +反向(过程(s.子串(l+1,r)))
    +s.r(r+1)
    }
    
    我们可以将
    反向
    定义为-

    const reverse=(s=”“)=>
    s、 长度
    ? 反向(s.substr(1))+s.substr(0,1)
    : ""
    
    const输入=
    [“foo(bar)”、“(bar)”、“foo(bar)blim”、“foo(foo(bar))blim”、“foo(foo(bar)ddas)blim”、“foo(foo(b(tu)ar)ddas)blim”]
    预期常数=
    [“foorab”、“rab”、“foorabblim”、“foobaroofblim”、“foodsaddbaroofblim”、“foodsaddbutaroofblim”]
    常数结果=
    输入。映射(过程)//
    s、 长度
    ? 反向(s.substr(1))+s.substr(0,1)
    : ""
    功能流程(s=”“)
    {const l=s.indexOf(“”)
    常数r=s.lastIndexOf(“)”)
    如果(l==-1&&r===-1)
    返回s
    else if(l==-1 | r==-1)
    返回“”
    其他的
    返回s.子字符串(0,l)
    +反向(过程(s.子串(l+1,r)))
    +s.r(r+1)
    }
    常量输入=
    [“foo(bar)”、“(bar)”、“foo(bar)blim”、“foo(foo(bar))blim”、“foo(foo(bar)ddas)blim”、“foo(foo(b(tu)ar)ddas)blim”]
    预期常数=
    [“foorab”、“rab”、“foorabblim”、“foobaroofblim”、“foodsaddbaroofblim”、“foodsaddbutaroofblim”]
    常数结果=
    
    inputs.map(process)/当存在多组未列出的参数时,此问题的其他一些答案会产生错误的结果-

    console.log(进程(“你好(世界)是(否)阳(阴)”)
    //helloniy(gnaynosey)dlrow
    控制台日志(过程(“ab(cd(ef(gh)))ij(k(lm)n)opqr(stu(vw)x)yz”))
    //hgopqr(stu(vwdcyz
    //哦,不!
    

    lex

    让我们尝试另一种解决问题的方法。首先,
    lexer
    创建一个词素流-

    function* lexer(s = "")
    { const leftParen =
        { type: "leftParen" }
    
      const rightParen =
        { type: "rightParen" }
    
      const str = value =>
        ({ type: "str", value })
      
      let r =
        ""
      
      for (const c of s)
        if (c === "(")
          (yield str(r), yield leftParen, r = "")
        else if (c === ")")
          (yield str(r), yield rightParen, r = "")
        else
          r = r + c
    
      yield str(r)
    }
    
    让我们看看
    lexer
    是如何工作的-

    lexer(“这(是(非常(嵌套))但是(没有)”)/=>。。。
    
    {type:“str”,value:“this”}
    {type:“leftParen”}
    {type:“str”,value:“is”}
    {type:“leftParen”}
    {类型:“str”,值:“very”}
    {type:“leftParen”}
    {类型:“str”,值:“嵌套”}
    {type:“rightParen”}
    {类型:“str”,值:}
    {type:“rightParen”}
    {类型:“str”,值:}
    {type:“rightParen”}
    {type:“str”,value:“but”}
    {type:“leftParen”}
    {类型:“str”,值:“nothere”}
    {type:“rightParen”}
    {类型:“str”,值:}
    

    解析

    接下来,
    parser
    获取词素并生成一个抽象语法树-

    函数解析器(词素)
    {const concat=\=>
    ({类型:“concat”,值:[]})
    const rev=\uu=>
    ({类型:“rev”,值:[]})
    常数r=
    [concat()]
    for(词素常量)
    如果(t.type==“str”)
    r[0]。值。取消移位(t)
    else if(t.type==“leftParen”)
    r、 取消移位(rev())
    else if(t.type==“rightParen”)
    如果(r.长度1)
    抛出错误(“预期“')”)
    其他的
    返回r[0]
    }
    
    现在让我们看看
    解析器的效果-

    parser(lexer(“this(非常(嵌套)))但是(nothere)”)/=>。。。
    
    {键入:“concat”
    ,价值观:
    [{类型:“str”,值:}
    ,{类型:“rev”
    ,价值观:
    [{type:“str”,value:“nothere”}
    ]
    }
    ,{type:“str”,value:“but”},
    {类型:“rev”
    ,价值观:
    [{类型:“str”,值:}
    ,{类型:“rev”
    价值
    
    foorab, rab, foorabblim, foobaroofblim, foosaddbaroofblim, foosaddbutaroofblim
    foorab, rab, foorabblim, foobaroofblim, foosaddbaroofblim, foosaddbutaroofblim
    
    function* lexer(s = "")
    { const leftParen =
        { type: "leftParen" }
    
      const rightParen =
        { type: "rightParen" }
    
      const str = value =>
        ({ type: "str", value })
      
      let r =
        ""
      
      for (const c of s)
        if (c === "(")
          (yield str(r), yield leftParen, r = "")
        else if (c === ")")
          (yield str(r), yield rightParen, r = "")
        else
          r = r + c
    
      yield str(r)
    }
    
    foorab, rab, foorabblim, foobaroofblim, foosaddbaroofblim, foosaddbutaroofblim
    foorab, rab, foorabblim, foobaroofblim, foosaddbaroofblim, foosaddbutaroofblim
    
    char = "a" | "b" | "c" | "d" ...
         | "A" | "B" | "C" | "D" ...
         | "1" | "2" | "3" | "4" ...
         | "!" | "@" | "#" | "$" ...
         | ...
    
    string = ""
           | char + string
    
    expr = string
         | expr + "(" + expr + ")" + expr