我试着在C ++中编写一个函数来比较两个字符串s1和s2,其中只有s2有'?'字符。 '?'字符代表匹配任何角色的能力, 包括空字符。例如,colo?r匹配“颜色”和“颜色”。 这个 查询应报告匹配的每个单词。其他例子:
您好:hello__True
你好:h?l?o - true(两者都充当通配符)
hllo:h?l?o - true(首先?作为空,第二个?充当通配符)
hlo:h ?? lo - true(两者都是空的)
你好:h?lo - false(?字符只能替换一个字符,而不是字符串)
你好:h ??? p - false(p确实匹配任何可能的字符选项)
我尝试使用循环使用很多函数,但我只能处理所有'?'的问题作为空或通配符。当一个人作为空行为而另一行作为通配符时,那么有许多不同的字符串可供比较,事情就会失控。
我的教授告诉递归是解决这个问题的关键,但我们还没有讨论过递归问题。 请帮我提供一些建议/代码,可以使用回溯技术来解决这个问题。
答案 0 :(得分:0)
基本上,你使用通配符查看字符串(我将从现在开始调用该字符串 pattern ):
如果模式的第一个字符是?
字符,那么请尝试从输入字符串中精确地使用该字符(另一个字符串没有通配符)。
如果模式的第一个字符是?
,那么您有两种情况:
?
应匹配一个字符(为了匹配完整的模式),所以只需使用输入中的下一个字符然后继续。?
不应与字符匹配,在这种情况下,您将继续使用模式中的下一个字符并保持输入字符串不变。当然,您无法知道在何时选择这些案例。因此,您需要能够回到那一点,以防您的猜测错误。
为此,你可以使用递归(或更准确地说:新的上下文,就局部变量而言,你从递归调用得到的):
您只需先使用剩余模式和输入字符串调用匹配函数,如果失败,则使用剩余模式和输入字符串调用匹配函数,而不使用其第一个字符(从而使?
消耗一个角色。)
示例:
pattern: s?y
input: say
模式的第一个字符是s
,这是正常的非通配符匹配,因此查看匹配的输入的第一个字符,同时移动:
pattern: ?y
input: ay
现在有一个匹配的通配符,所以假装它没有消耗任何角色,让我们看看它在哪里得到我们。使用以下命令调用匹配函数:
pattern: y
input: ay
哎呀,那不匹配(a != y
),所以此时返回false
。这将我们带回到我们称之为匹配函数的位置(在上面的步骤中),让我们留下:
pattern: ?y
input: ay
我们已经尝试将通配符匹配为无字符,现在尝试将其与任何字符匹配,从而消耗a
:
pattern: y
input: y
哇,匹配,并且下一次运行时两个字符串都是空的,所以我们有一个匹配!
这似乎是家庭作业,您可能必须在C ++中实现。我不会给你那个代码。相反,我会用不同的语言给你一个实现 - Clojure - 这应该可以让你进一步理解上面的算法。
(ns wildcards
(:refer-clojure))
(defn- dpr
"Debug printing with poor man's indendation"
[pattern & rest]
(print (repeat (- 6 (count pattern)) " "))
(apply println rest))
(defn wildcard-match [input pattern]
(println "wildcard-match " input pattern)
(if (or (empty? input) (empty? pattern))
;; One is empty, return true if both are
(and (empty? input) (empty? pattern))
;; Else
(if (= (first pattern) \?)
;; Wildcard, so with short ciruiting or:
(or (do
(dpr pattern "Try to match no character...")
(wildcard-match input (rest pattern)))
(do
(dpr pattern "Ok, so try to match any character...")
(recur (rest input) (rest pattern))))
;; Non-Wildcard, test for equality, and if equal, go on.
(and (= (first pattern) (first input))
(recur (rest input) (rest pattern))))))
(defn testcase [input pattern]
(println "#####################################")
(println "Trying to match" input "with" pattern)
(println "=>" (wildcard-match (seq input) (seq pattern)))
(println))
(doall (map #(testcase (first %) (second %))
[["hello" "hello"]
["hello" "h?l?o"]
["hllo" "h?l?o"]
["hlo" "h??lo"]
["hello" "h?lo"]
["hello" "h???p"]]))
你可以在这里看到这个被执行: http://ideone.com/8o4QdR
由于Clojure是一种强大的递归使用功能语言,因此你会看到很多递归。将其转换为更加命令式的语言(如C ++)应该可以摆脱大多数这些递归,特别是那些可以被循环替换的递归(即所有recur
次调用,只留下一次必要的递归)。