这是一个递归解决方案。
代码
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_length 和Integer#[]。
我们可以通过检查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。