【发布时间】:2010-12-27 08:05:20
【问题描述】:
这是一个挑战,要为一个相对琐碎的问题想出最优雅的 JavaScript、Ruby 或其他解决方案。
这个问题是Longest common substring problem 的一个更具体的情况。我只需要在数组中找到最长的公共 starting 子字符串。这大大简化了问题。
例如,[interspecies, interstelar, interstate] 中最长的子字符串是“inters”。不过,我不需要在[specifics, terrific] 中找到“ific”。
我已经通过在我的answer about shell-like tab-completion (test page here) 中快速编写一个 JavaScript 解决方案来解决这个问题。这是解决方案,稍作调整:
function common_substring(data) {
var i, ch, memo, idx = 0
do {
memo = null
for (i=0; i < data.length; i++) {
ch = data[i].charAt(idx)
if (!ch) break
if (!memo) memo = ch
else if (ch != memo) break
}
} while (i == data.length && idx < data.length && ++idx)
return (data[0] || '').slice(0, idx)
}
这个code is available in this Gist 以及 Ruby 中的类似解决方案。您可以将 gist 克隆为 git repo 进行尝试:
$ git clone git://gist.github.com/257891.git substring-challenge
我对这些解决方案不太满意。我有一种感觉,它们可能会以更优雅和更少的执行复杂性来解决——这就是我发布这个挑战的原因。
我将接受我认为最优雅或最简洁的解决方案作为答案。例如,这是我想出的一个疯狂的 Ruby hack——在 String 上定义 & 运算符:
# works with Ruby 1.8.7 and above
class String
def &(other)
difference = other.to_str.each_char.with_index.find { |ch, idx|
self[idx].nil? or ch != self[idx].chr
}
difference ? self[0, difference.last] : self
end
end
class Array
def common_substring
self.inject(nil) { |memo, str| memo.nil? ? str : memo & str }.to_s
end
end
JavaScript 或 Ruby 中的解决方案是首选,但您可以用其他语言展示聪明的解决方案,只要您解释发生了什么。请只使用标准库中的代码。
更新:我最喜欢的解决方案
我选择kennebec 的JavaScript sorting solution 作为“答案”,因为它让我觉得既出乎意料又是天才。如果我们忽略实际排序的复杂性(假设它被语言实现无限优化),解决方案的复杂性只是比较两个字符串。
其他出色的解决方案:
- FM 的"regex greed" 需要一两分钟才能掌握,但随后它的优雅就让你眼前一亮。 Yehuda Katz 也制作了a regex solution,但它更复杂
-
commonprefixin Python — Roberto Bonvallet 使用了一个用于处理文件系统路径的功能来解决这个问题 - Haskell one-liner 很短,好像被压缩了一样,很漂亮
- the straightforward Ruby one-liner
感谢参与!正如您从 cmets 中看到的,我学到了很多东西(甚至是关于 Ruby)。
【问题讨论】:
-
接受的答案展示了一个非常酷的解决方案。好吧,当然,答案本身是错误的,但谁在乎呢,这个想法太酷了;)
-
我将这个问题作为题外话来结束,因为它是关于代码打高尔夫球和/或代码审查,而不是离散的编程问题。
标签: javascript python ruby haskell longest-prefix