3

在编写比较 2 个单词的方法时,如何检查单词是否只有 1 个字母不同?我假设单词的长度和字母顺序无关紧要(参见“cobra”、“bravo”)。

def one_letter_apart?(word1, word2)

我希望得到以下结果:

one_letter_apart?("abra","abro") == true
one_letter_apart?("cobra","bravo") == true
one_letter_apart?("bravo","tabby") == false
one_letter_apart?("abc","cab") == false

我尝试了几种操作它们的方法(拆分、排序、然后设置相等并添加到新数组、然后计数),但到目前为止还没有奏效。任何想法都非常感谢。

4

4 回答 4

5

检查 Levenshtein 距离

你想要莱文斯坦距离。例如,使用文本 gem

require 'text'

def one_letter_apart? string1, string2
  Text::Levenshtein.distance(string1, string2).eql? 1
end

one_letter_apart? "abra", "abro"
# => true 
one_letter_apart? "cobra", "bravo"
# => false 
于 2013-06-11T18:07:03.560 回答
5

这个利用了String#sub仅替换它找到的第一件事的事实。

def one_different_char?(str, other)
  other_str = other.dup
  str.chars{|char| other_str.sub!(char, '')} #sub! just replaces just one occurence of char
  other_str.size == 1
end


test_set = [["abra","abro"],["cobra","bravo"],["bravo","tabby"],["abc","cab"]]
test_set.each{|first, second| puts one_different_char?(first, second) }

#true
#true
#false
#false
于 2013-06-11T18:57:05.480 回答
1
def one_letter_apart?(s1, s2)
  return false if s1.length != s2.length

  a2 = s2.chars.to_a
  s1.chars.each do |c|
    if i = a2.index(c)
      a2.delete_at(i)
    end
  end

  a2.length == 1
end

one_letter_apart?("abra","abro") == true
# => true
one_letter_apart?("cobra","bravo") == true
# => true
one_letter_apart?("bravo","tabby") == false
# => true
one_letter_apart?("abc","cab") == false
# => true

更新:回答你关于它是如何工作的问题:这是与 steenslag 完全相同的通用算​​法,但我没有想到用它String#sub!来进行删除,所以我转换为数组并使用 和 的组合indexdelete_at删除第一次出现给定字符的。天真的方法是a2.delete_at(a2.index(c)),但如果字符c不存在于 中a2,则index返回nil,这是 的无效输入delete_at。解决方法是只调用delete_atifindex返回的东西 non- nil,这就是我所做的。 i被声明并设置为a2.index(c),并且该赋值的值由 评估if。它与以下内容相同:

i = a2.index(c)
if i
  # ...

我更喜欢 steenslag 的方法,如果我想到的话,我会做同样的事情String#sub!

于 2013-06-11T18:55:43.183 回答
-1

如果两个字符串的长度相等且只有一个不同的字母,而所有其他字母都在相同的位置,则此函数返回 true:

def one_letter_apart? string1, string2
  return false if string1.size != string2.size
  found = false
  (0...string1.size).each do |i|
    next if string1[i] == string1[i]
    return false if found  # if found is already true, and we found another difference, then result is false.
    found = true  # We found the first difference.
  end
  found  # True if only one difference was found.
end

此函数也处理错误位置的字母(如“cobra”和“bravo”):

def one_letter_apart? string1, string2
  letters1 = string1.chars.each_with_object(Hash.new(0)) { |c, h| h[c] += 1 }
  letters2 = string2.chars.each_with_object(Hash.new(0)) { |c, h| h[c] -= 1 }
  diff = letters1.merge(letters2) { |key, count1, count2| count1 + count2 }
  return diff.values.select { |v| v != 0 } .sort == [-1, 1]
end
于 2013-06-11T18:24:24.540 回答