【问题标题】:decodeString: regex solutiondecodeString:正则表达式解决方案
【发布时间】:2018-11-21 00:36:15
【问题描述】:

提示: 给定一个编码字符串,返回其对应的解码字符串。编码规则是:k[encoded_string],其中方括号内的encoded_string恰好重复k次。注意:k 保证为正整数。

对于 s = "4[ab]",输出应该是 decodeString(s) = "abababab" 对于 s = "2[b3[a]]",输出应该是 decodeString(s) = "baaabaaa"

我的回答:

let decodeString = function(s) {

  const replaced = s.replace((/(\d+)\[([a-z]*)\]/), (match, num, substr) => {
    return substr.repeat(num);
  })

  return replaced.indexOf('[') > -1 ? decodeString(replaced) : replaced; 

};

此解决方案适用于较小的输入,如 "3[a]2[bc]",但对于更复杂的输入,如 "3[a]2[b4[F]c]",我会出现堆栈溢出。有没有办法迭代地执行此操作以避免使用调用堆栈?是否可以仅通过使用正则表达式来解决这个问题?非常感谢任何帮助!

【问题讨论】:

  • 使用递归函数和你的正则表达式是可能的
  • 这是编写基本词法分析器、解析器和求值器的绝佳练习。我强烈建议您尝试一下。它将向您展示如何在没有高度复杂的正则表达式引擎的情况下解决此问题。

标签: javascript regex string recursion decode


【解决方案1】:

function decodeString(str){
	let regex = /(\d+)\[([a-z]*)\]/gi;
	let result = str.replace(regex, (match, num, substr) => substr.repeat(num));
	let recall = regex.test(result);
	if(recall){
		return decodeString(result);
	}
	return result;
}

console.log(
  decodeString("4[ab]"),
  decodeString("2[b3[a]]"),
  decodeString("3[a]2[b4[F]c]")
)

【讨论】:

  • 感谢您的帮助。我认为您的解决方案与我的逻辑相同。它还达到输入"3[a]2[b4[F]c]" 的最大调用堆栈。有什么办法可以避免这种情况?
  • 为什么您甚至建议将打高尔夫球的代码作为 SO 问题的解决方案?只需删除打高尔夫球的部分...
  • @AlecDavidson 抱歉,我只是发现问题是您的正则表达式中缺少 i 以忽略区分大小写
  • @Luis 是的!谢谢!问题是缺少 i
【解决方案2】:

您可以根据相同的条件将递归调用替换为 while 循环:

function decodeString(s) {
    while (s.includes("[")) {
        s = s.replace(/(\d+)\[([a-z]*)\]/, (match, num, substr) => substr.repeat(num));
    }
    return s;
}

console.log(decodeString("2[b3[a]]"));

【讨论】:

  • 是的。这次真是万分感谢。这是我一直在寻找的迭代解决方案。堆栈溢出实际上是因为正则表达式中缺少 i 标志
  • 确实,如果您的大写或左大括号多于右大括号,或者前面缺少数字,或者与其中任何一个都不匹配的字符,......它不会停止。如果不能保证输入与模式匹配,最好比较替换前后的字符串:if nothing changed: exit;
【解决方案3】:

有趣的是,几行优雅的正则表达式代码将重现遍历字符串的方法需要 60 行左右的代码才能完成的结果。但是,我认为对我遇到的各种实现进行基准测试也会很有趣。

我发现纯粹的迭代方法,递归调用嵌套括号,比其他实现要快得多。结果如下:

  1. 迭代字符串,递归调用嵌套括号的过程:136,943 ops/sec
  2. 不使用递归过程迭代字符串:85,775 ops/sec
  3. Luis Felipe 的正则表达式:81,197 ops/sec
  4. trincot 的正则表达式,用 while 循环替换递归调用:80,784 ops/sec

当然,1 到 2 之间的其他变量可能会显着减慢后者的速度。但乍一看,在这种情况下递归提高性能的假设似乎是合理的。

这是jsperf

实现 1 是 here。实现 2 是here。有趣的是,实现 1 是唯一一个运行速度足以通过CodeSignal 测试的实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 2013-09-29
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 2011-05-03
    相关资源
    最近更新 更多