【问题标题】:Given a word, I need to get all variations of spaces for that word给定一个单词,我需要获取该单词的所有空格变体
【发布时间】:2019-04-26 21:58:36
【问题描述】:

给定一个单词,让我们使用“Stack”,我想得到该单词的所有变体,带有空格。

例如,我会寻找这样的数组:

[
  'S tack',
  'S t ack',
  'S t a ck',
  'S t a c k',
  'Stac k',
  'Sta c k',
  'St a c k',
   ...
]

我没有任何代码可显示,因为我无法解决此问题。我有一种感觉,我需要在每个字母处拆分单词并使用循环添加空格,然后将该单词添加到数组中,但我不确定这背后的逻辑。我假设我需要使用模数 % 但同样,我真的不知道。

我为此使用了 Ruby,但鉴于这更像是一个逻辑问题,使用哪种语言并不重要。

【问题讨论】:

  • 提示:每对字母之间,要么有空格,要么没有。您如何计算布尔值列表的所有可能组合?
  • 你不会错过输出中的很多变化吗?
  • 假设@Marcin 是正确的,您确实需要编辑问题以添加缺失值,或者至少将”...,” 添加到数组中。另一方面,如果数组如您所愿,您需要解释其底层模式。不回答一个明显有效的问题是不尊重的,在你回答之前,你肯定会继续吸引反对票。

标签: arrays ruby loops logic


【解决方案1】:
def combine_string_with(s, delimiter = " ")
  combinations = (1..s.size - 1).flat_map { |n| (1..s.size - 1).to_a.combination(n).to_a }
  combinations.map do |arr|
    arr.reverse.each_with_object(s.dup) do |i, string|
      string.insert(i, delimiter)
    end
  end
end

combine_string_with("Stack")

生产

["S tack",
 "St ack",
 "Sta ck",
 "Stac k",
 "S t ack",
 "S ta ck",
 "S tac k",
 "St a ck",
 "St ac k",
 "Sta c k",
 "S t a ck",
 "S t ac k",
 "S ta c k",
 "St a c k",
 "S t a c k"]

combinations 是一个包含所有索引的数组,用于放置我们的分隔符,即

[[1], [2], [3], [4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4], [1, 2, 3, 4]]

在遍历组合时调用 reverse 以从末尾插入分隔符,因此索引将在向后移动时保持匹配。

【讨论】:

  • combination 的块也可以写成:letters = s.chars; arr.each { |i| letters[i] = delimiter + letters[i] }; letters.join
  • arr's 块也可以写成:letters[i].prepend delimiter
【解决方案2】:

这是一个递归解决方案。

代码

def recurse(word)
  return [word] if word.size == 1
  first_char = word[0]
  recurse(word[1..-1]).flat_map { |s| [first_char+s, first_char+' '+s] }
end

示例

arr = recurse 'Stack'
  #=> ["Stack", "S tack", "St ack", "S t ack", "Sta ck", "S ta ck", "St a ck", "S t a ck",
  #    "Stac k", "S tac k", "St ac k", "S t ac k", "Sta c k", "S ta c k", "St a c k", 
  #    "S t a c k"]

说明

此方法执行的步骤如下所示。请注意,每次调用 recurse 时,打印行都会缩进 4 个空格。

INDENT = 4
@off = 0

def s
  ' '*@off
end

def indent
  @off += INDENT
end

def undent
  @off -= INDENT
end

def recurse(word)
  puts "#{s}Entering recurse(\"#{word}\")"
  puts "#{s}Returning [\"#{word}\"] as \"#{word}\".size == 1" if word.size == 1
  return [word] if word.size == 1
  puts "#{s}Calling recurse(\"#{word[1..-1]}\")"
  indent
  a1 = recurse(word[1..-1])
  undent
  puts "#{s}recurse(\"#{word[1..-1]}\") returned a1 = #{a1}"
  first_char = word[0]
  puts "#{s}first_char = \"#{first_char}\""
  a2 = a1.flat_map { |s| [first_char+s, first_char+' '+s] }
  puts "#{s}Returning a1.flat_map { |s| first_char+s, first_char + ' ' + s] } = "
  puts "#{s}  #{a2}"   
  a2
end

recurse("dogs")
  #=> ["dogs", "d ogs", "do gs", "d o gs", "dog s", "d og s", "do g s", "d o g s"]

打印

Entering recurse("dogs")
Calling recurse("ogs")
    Entering recurse("ogs")
    Calling recurse("gs")
        Entering recurse("gs")
        Calling recurse("s")
            Entering recurse("s")
            Returning ["s"] as "s".size == 1
        recurse("s") returned a1 = ["s"]
        first_char = "g"
        Returning a1.flat_map { |s| first_char+s, first_char + ' ' + s] } =
          ["gs", "g s"]
    recurse("gs") returned a1 = ["gs", "g s"]
    first_char = "o"
    Returning a1.flat_map { |s| first_char+s, first_char + ' ' + s] } =
      ["ogs", "o gs", "og s", "o g s"]
recurse("ogs") returned a1 = ["ogs", "o gs", "og s", "o g s"]
first_char = "d"
Returning a1.flat_map { |s| first_char+s, first_char + ' ' + s] } =
  ["dogs", "d ogs", "do gs", "d o gs", "dog s", "d og s", "do g s", "d o g s"]

@Marcin 答案的变体

word = 'Stack'
word_chars = word.chars
last_idx = word.size-1
(0..2**last_idx-1).map do |n|
  n.bit_length.times.with_object(word_chars.dup) do |i,arr|
    c = arr[last_idx-i]
    arr[last_idx-i] = n[i] == 1 ? (' '+c) : c
  end.join
end
  #=> ["Stack", "Stac k", "Sta ck", "Sta c k", "St ack", "St ac k", "St a ck",
  #    "St a c k", "S tack", "S tac k", "S ta ck", "S ta c k", "S t ack", "S t ac k",
  #    "S t a ck", "S t a c k"]

参见Integer#bit_lengthInteger#[]

我们可以通过检查n 的位将(0..2**last_idx-1) 范围内的每个数字n 映射到所需数组的一个元素。具体来说,如果ith 有效位是1,则字符word[word.size-1-i] 将在前面加上一个空格;如果是0,则该字符将不会以空格开头。

对于word = 'Stack'last_idx = 'Stack'.size-1 #=> 4,所以范围是0..2**4-1 #=> 0..15。这些数字对应于二进制数0, 0b1, 0b10, 0b11, 0b110,...0b1111。此范围内的一个数字是11,其二进制表示由11.to_s(2) #=> "1011"0b1011 给出。由于第三个最不重要的是0"Stack" 中的"a" 将保持不变,但"t""c""k" 将分别映射到" t"" c"" k"(因为它们对应于0b1011中的1),从而产生字符串["S", " t", "a", " c", " k"].join #=> => "S ta c k"

请注意,这种技术或多或少等同于使用方法Array#combination

【讨论】:

  • @iGian,我提供了解释。
【解决方案3】:

使用索引的其他选项,一个衬里:

string = 'Stack'

(1..string.size).map.with_object([]) { |n, res| (1..string.size-1).to_a.combination(n).map { |idxs| idxs.reverse.each.with_object(string.dup) { |i, tmp| res << tmp.insert(i, ' ') } } }.uniq

#=> ["S tack", "St ack", "Sta ck", "Stac k", "S t ack", "S ta ck", "S tac k", "St a ck", "St ac k", "Sta c k", "S t a ck", "S t ac k", "S ta c k", "St a c k", "S t a c k"]

【讨论】:

【解决方案4】:

跟进 Jörg W Mittag 的评论:

'Stack'.
  split(//).
  map { |l| [l, "#{l} "] }.
  reduce(&:product).
  map(&:join)

【讨论】:

  • 这将返回末尾带有空格的字符串,这与其他解决方案不同,但如果需要,之后可以轻松清理。此外,split(//) 可以替换为 each_char
  • @Marcin,而不是最后清理,将"Stack"更改为"Stac"map(&amp;:join)更改为map { |a| (a &lt;&lt; 'k').join }效率更高。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多