我给了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,我已经尝试过操纵函数并将它们发送到递归但没有用。我很高兴被指向正确的方向,代码或可能重构的伪代码。
(省略了一些关于括号的扩展方法,我认为它们清楚了解它们的作用)
答案 0 :(得分:5)
另一种可能更简单的解决方法是在迭代字符时保持一叠括号。
当您遇到另一个括号时:
如果它与堆栈顶部匹配,则弹出堆栈顶部;
如果它与堆栈顶部不匹配(或堆栈为空),则将其推入堆栈。
如果最后在堆栈上保留任何括号,则表示它们不匹配,答案为false
。如果堆栈结束为空,则答案为true
。
这是正确的,因为序列中位置i
的括号可以匹配位置j
的另一个括号,只有当它们之间没有不匹配的不匹配的括号时(在位置k
,i < 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);
}
}