给定一个单词,我需要获取该单词的所有空格变化

时间:2018-11-24 18:16:34

标签: arrays ruby loops logic

给出一个词,让我们使用“堆栈”,我想获得该词带有空格的所有变体。

例如,我要寻找一个像这样的数组:

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

我没有任何代码可以显示,因为我无法解决此问题。我有一种感觉,我需要在每个字母处拆分单词,然后使用循环添加空格,然后将该单词添加到数组中,但是我不确定其背后的逻辑。我以为我需要使用模数%,但是我也不是很清楚。

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

4 个答案:

答案 0 :(得分:5)

这是一个递归解决方案。

代码

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映射到所需数组的一个元素。具体来说,如果第i个有效位是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"a"中的"Stack"将保持不变,但是"t""c""k"将分别映射到" t"" c"" k"(因为它们对应于1中的0b1011),产生字符串["S", " t", "a", " c", " k"].join #=> => "S ta c k"

请注意,此技术多少等效于使用方法Array#combination

答案 1 :(得分:2)

9

产生

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]] ,以便从末尾插入定界符,因此索引在向后移动时将保持匹配。

答案 2 :(得分:2)

关注JörgW Mittag的评论:

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

答案 3 :(得分:0)

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

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"]