匹配kotlin方式

时间:2017-08-18 20:06:11

标签: parsing kotlin

我给了Kotlin一个去;内容编码,我有一个字符的ArrayList,我想根据括号的匹配方式进行分类:

(abcde)  // ok characters other than brackets can go anywhere
)abcde(  // ok matching the brackets 'invertedly' are ok
(({()})) // ok 
)()()([] // ok 
([)]     // bad can't have different overlapping bracket pairs
(((((    // bad all brackets need to have a match

我的解决方案出来了(递归):

//charList is a property
//Recursion starter'upper
private fun classifyListOfCharacters() : Boolean{
    var j = 0
    while (j < charList.size ) {
        if (charList[j].isBracket()){
            j = checkMatchingBrackets(j+1, charList[j])
        }
        j++
    }
    return j == commandList.size
}

private fun checkMatchingBrackets(i: Int, firstBracket :Char) : Int{
    var j = i
    while (j < charList.size ) {
        if (charList[j].isBracket()){
            if (charList[j].matchesBracket(firstBracket)){ 
                return j //Matched bracket normal/inverted
            }
            j = checkMatchingBrackets(j+1, charList[j])
        }
        j++
    }
    return j
}

这有效,但这是你在Kotlin的表现吗?感觉就像我在Kotlin语法

中编写了java一样

发现这个Functional languages better at recursion,我已经尝试过操纵函数并将它们发送到递归但没有用。我很高兴被指向正确的方向,代码或可能重构的伪代码。

(省略了一些关于括号的扩展方法,我认为它们清楚了解它们的作用)

2 个答案:

答案 0 :(得分:5)

另一种可能更简单的解决方法是在迭代字符时保持一叠括号。

当您遇到另一个括号时:

  • 如果它与堆栈顶部匹配,则弹出堆栈顶部;

  • 如果它与堆栈顶部不匹配(或堆栈为空),则将其推入堆栈。

如果最后在堆栈上保留任何括号,则表示它们不匹配,答案为false。如果堆栈结束为空,则答案为true

这是正确的,因为序列中位置i的括号可以匹配位置j的另一个括号,只有当它们之间没有不匹配的不匹配的括号时(在位置ki < k < j)。堆栈算法正好模拟了这种匹配逻辑。

基本上,这个算法可以在一个for - 循环中实现:

val stack = Stack<Char>()

for (c in charList) {
    if (!c.isBracket())
        continue

    if (stack.isNotEmpty() && c.matchesBracket(stack.peek())) {
        stack.pop()
    } else {
        stack.push(c)
    }
}

return stack.isEmpty()

我已重复使用您的扩展程序c.isBracket(...)c.matchesBracket(...)Stack<T>是JDK类。

此算法隐藏递归和括号嵌套在抽象括号堆栈内的括号。比较:您当前的方法隐式使用函数调用堆栈而不是括号堆栈,但目的是相同的:它要么找到顶部字符的匹配项,要么在顶部用另一个字符进行更深层次的递归调用。

答案 1 :(得分:2)

Hotkey的答案(使用for循环)很棒。但是,您要求优化的递归解决方案。这是一个优化的tail recursive函数(注意函数前的tailrec修饰符):

tailrec fun isBalanced(input: List<Char>, stack: Stack<Char>): Boolean = when {

    input.isEmpty() -> stack.isEmpty()

    else -> {

        val c = input.first()

        if (c.isBracket()) {
            if (stack.isNotEmpty() && c.matchesBracket(stack.peek())) {
                stack.pop()
            } else {
                stack.push(c)
            }
        }

        isBalanced(input.subList(1, input.size), stack)

    }
}

fun main(args: Array<String>) {
    println("check: ${isBalanced("(abcde)".toList(), Stack())}")
}

此函数调用自身,直到输入变为空,如果输入变空,如果堆栈为空,则返回true。

如果我们查看生成的字节码的反编译Java等价物,这个递归已经被编译器优化为有效的while循环,所以我们不会得到StackOverflowException(删除了Intrinsics null检查):

public static final boolean isBalanced(@NotNull String input, @NotNull Stack stack) {
      while(true) {
         CharSequence c = (CharSequence)input;
         if(c.length() == 0) {
            return stack.isEmpty();
         }

         char c1 = StringsKt.first((CharSequence)input);
         if(isBracket(c1)) {
            Collection var3 = (Collection)stack;
            if(!var3.isEmpty() && matchesBracket(c1, ((Character)stack.peek()).charValue())) {
               stack.pop();
            } else {
               stack.push(Character.valueOf(c1));
            }
         }

         input = StringsKt.drop(input, 1);
      }
   }