我使用任何一个内置函数(如find(),replace()等)在网络中搜索的每个函数。我在学术书籍,图书馆和互联网上做过研究,但我找不到解决方案。请问您是否可以提供实现上述功能的算法,而无需使用任何内置函数?
答案 0 :(得分:2)
好吧,让我们先尝试解决一些更简单的问题,然后逐步解决字符串替换问题。首先,我们如何确定两个字符串是否相等?相当直截了当吧?如果字符串具有相同的长度,并且具有相同顺序的相同字符,那么它们是相等的:
(defn str-eq? [s1 s2]
(and (= (count s1) (count s2))
(every? identity
(map = s1 s2))))
好的,让我们尝试检查字符串是否有其他字符串作为前缀。事实证明这有一个几乎相同的解决方案,我们只是简化了两个字符串长度相同的要求:
(defn str-prefix? [s prefix]
(and (>= (count s) (count prefix))
(every? identity
(map = s prefix))))
现在,让我们开始考虑如何在某些字符串中找到所有出现的字符串s1。好吧,如果我们采用s的所有后缀,从最长到最短排序,我们可以通过检查哪个后缀s1是前缀来确定s1在s1中出现的位置:
(defn str-suffixes [s]
(->> s
(iterate next)
(take (inc (count s))) ;; make sure we include the empty string
(map #(apply clojure.core/str %))))
(defn str-find [s s1]
(->> (str-suffixes s)
(map (fn [index suffix]
(if (str-prefix? suffix s1)
index
nil))
(iterate inc 0))
(filter identity)))
最后,是替换字符串的时间。我们将从简单的情况开始,其中字符串s1在索引处出现在字符串s中最多一次。只需将索引前的所有内容与替换字符串s2以及s中s1出现后的所有内容连接起来:
(defn str-replace [s s1 s2]
(reduce (fn [s index]
(apply clojure.core/str
(concat (take index s)
s2
(drop (+ index (count s1)) s))))
s
(str-find s s1)))
如果s1多次出现,您会发现这不起作用。这是因为str-find以递增的顺序给出了结果。我们每次更换字符串时,都会在字符串后面使索引无效。要解决这个问题,我们只需处理从最大到最小的每个索引:
(defn str-replace [s s1 s2]
(reduce (fn [s index]
(apply clojure.core/str
(concat (take index s)
s2
(drop (+ index (count s1)) s))))
s
(sort > (str-find s s1))))
这就是行动:
(str-replace "foobar" "foo" "baz")
=> "bazbar"
(str-replace "foobar" "bar" "baz")
=> "foobaz"
(str-replace "foobarbarfoo" "bar" "bazz")
=> "foobazzbazzfoo"
(str-replace "foobar" "z" "baz")
=> "foobar"
当解决这样的问题时,有助于考虑其他类似的操作,以及它们如何与您尝试实施的操作相关联。如果您有任何问题,请告诉我。