首页 > 解决方案 > Codewars:“返回或旋转”:为什么我尝试的解决方案不起作用?

问题描述

这些是 Codewars ( https://www.codewars.com/kata/56b5afb4ed1f6d5fb0000991/train/ruby ) 上给出的说明:
输入是字符串字符串。将字符串切成大小为 sz 的块(这里的块是初始字符串的子字符串)(如果最后一个块的大小小于 sz,则忽略它)。

如果一个块表示一个整数,例如其数字的立方和可以被 2 整除,则反转该块;否则将其向左旋转一个位置。将这些修改后的块放在一起并将结果作为字符串返回。

如果

sz <= 0 或者如果 str 为空,则返回 ""
sz 大于 (>) str 的长度,因此不可能获取大小为 sz 的块,因此返回 ""。

Examples:
revrot("123456987654", 6) --> "234561876549"
revrot("123456987653", 6) --> "234561356789"
revrot("66443875", 4) --> "44668753"
revrot("66443875", 8) --> "64438756"
revrot("664438769", 8) --> "67834466"
revrot("123456779", 8) --> "23456771"
revrot("", 8) --> ""
revrot("123456779", 0) --> "" 
revrot("563000655734469485", 4) --> "0365065073456944"

这是我的代码(在 Ruby 中):

def revrot(str, sz)
    # your code
  if sz > str.length || str.empty? || sz <= 0
    ""
  else
    arr = []
    
    while str.length >= sz
      arr << str.slice!(0,sz)
    end
    
    arr.map! do |chunk|
      if chunk.to_i.digits.reduce(0) {|s, n| s + n**3} % 2 == 0
        chunk.reverse
      else
         chunk.chars.rotate.join
      end
    end
    
    arr.join
  end
end

它通过了 13/14 测试,我得到的错误如下:

STDERR/runner/frameworks/ruby/cw-2.rb:38:in `expect': Expected: "", instead got: "095131824330999134303813797692546166281332005837243199648332767146500044" (Test::Error)
    from /runner/frameworks/ruby/cw-2.rb:115:in `assert_equals'
    from main.rb:26:in `testing'
    from main.rb:84:in `random_tests'
    from main.rb:89:in `<main>'

我不确定我做错了什么,我一直试图找出它可能是一个多小时。你可以帮帮我吗?

标签: ruby

解决方案


我会让其他人识别您代码的问题。我只是想展示如何加快解决方案。(我不会包含处理边缘情况的代码,例如字符串为空。)

您可以利用两个观察结果:

  • 当且仅当整数是奇数时,整数的立方是奇数;和
  • 当且仅当奇数的个数是奇数时,整数集合的总和是奇数。

因此我们可以写

def sum_of_cube_odd?(str)
  str.each_char.count { |c| c.to_i.odd? }.odd?
end

考虑上一个示例中的 4 位数字组"563000655734469485"

sum_of_cube_odd? "5630" #=> false (so reverse -> "0365")
sum_of_cube_odd? "0065" #=> true  (so rotate  -> "0650")
sum_of_cube_odd? "5734" #=> true  (so rotate  -> "7345")
sum_of_cube_odd? "4694" #=> true  (so rotate  -> "6944")

所以我们要返回"0365065073456944"


让我们创建另一个助手。

def rotate_chars_left(str)
  str[1..-1] << s[0]
end
rotate_chars_left "0065" #=> "0650"
rotate_chars_left "5734" #=> "7345"
rotate_chars_left "4694" #=> "6944"

我们现在可以编写 main 方法了。

def revrot(str, sz)
  str.gsub(/.{,#{sz}}/) do |s|
    if s.size < sz
      ''
    elsif sum_of_cube_odd?(s)
      rotate_chars_left(s)
    else
      s.reverse
    end
  end
end
revrot("123456987654", 6)       #=>     "234561876549"
revrot("123456987653", 6)       #=>     "234561356789"
revrot("66443875", 4)           #=>         "44668753"
revrot("66443875", 8)           #=>         "64438756"
revrot("664438769", 8)          #=>         "67834466"
revrot("123456779", 8)          #=>         "23456771"
revrot("563000655734469485", 4) #=> "0365065073456944"

写起来可能会快一些

require 'set'
ODD_DIGITS = ['1', '3', '5', '7', '9'].to_set
  #=> #<Set: {"1", "3", "5", "7", "9"}>
def sum_of_cube_odd?(str)
  str.each_char.count { |c| ODD_DIGITS.include?(c) }.odd?
end

推荐阅读