代码战-大小写字母被视为同一字符- Ruby 2.5

5vf7fwbs  于 2022-11-29  发布在  Ruby
关注(0)|答案(2)|浏览(204)

所以我在这个卡塔:
`

def  first_non_repeating_letter(s) 
  a = s.chars
  a.select! { |char| a.count(char) == 1 }
  if a.empty?
    ("")
  else
    a.first
  end
end

我唯一缺少的就是 作为一项附加挑战,大写字母与小写字母被视为同一字符,但函数应返回**首字母**得正确大小写***.例如,输入“sTreSS”应返回“T.”s.downcase.chars在这里不适用。我尝试了.casecmp`,但仍然不成功。我应该使用正则表达式吗?

nhn9ugyo

nhn9ugyo1#

如果给定的字符串是s,那么计算复杂度显然至少是O(s.size)(因为我们需要检查整个字符串以确认给定的字符在字符串中只出现一次)。因此,我们可以寻找一个具有相同计算复杂度的方法,最好是使用相对高效的Ruby内置方法,并且易于理解和测试。
假设给定的字符串如下:

s = "TgHEtGgh"

第一个只出现一次的字符(假设不考虑大小写)为"E"
作为第一步,我们可能希望计算字符串中每个字符的频率,小写和大写字符被视为1:

sdn = s.downcase
  #=> "tghetggh"
enum = sdn.each_char 
  #=> #<Enumerator: "tghetggh":each_char>
h = enum.tally
  #=> {"t"=>2, "g"=>3, "h"=>2, "e"=>1}

这使用了String#downcase,String#each_char和Enumerable#tally方法。这些方法的计算复杂度都是O(s.size),所以计算h的复杂度是一样的。作为奖励,这些方法都是用C实现的。
当然,我们可以链接这些方法:

h = s.downcase.each_char.tally
  #=> {"t"=>2, "g"=>3, "h"=>2, "e"=>1}

现在我们可以简单地遍历字符串s的字符,直到找到一个字符c,其中h[c.downcase] == 1true

s.each_char.find { |c| h[c.downcase] == 1 }
  #=> "E"

请参阅可枚举的#find。
对于这最后一步具有O(s.size)的计算复杂度,计算h[c.downcase]的计算复杂度必须等于1。事实上,哈希键查找的计算复杂度略大于1,但从实际Angular 来看,我们可以假设它等于1
1.注意,我们可以通过先写arr = sdn.chars #=> ["t", "g", "h", "e", "t", "g", "g", "h"],再写h = arr.tally来获得相同的结果。这样做的缺点是,与String#each_char不同,String#chars创建一个临时数组,消耗内存,尽管在这种情况下,使用each_char节省的内存可能是最小的。

yptwkmov

yptwkmov2#

这在你的实现中有点棘手,因为现在你没有任何显式的比较操作,而是使用Array#count
问题是这种实现不仅不灵活,而且效率也非常低。它的时间复杂度为O(n^2)(因为对于select遍历的每个元素,你都要在整个数组上调用count),所以对于足够大的输入,你的实现会非常慢。
好的方面是,解决了性能问题之后,您也可以轻松地实现这一额外的挑战(因为比较操作将变得显式,因此您可以只对需要进行降级的内容进行降级,而不会影响输入本身)。
让我们考虑一下通用的解决方案。什么是“非重复”字符?它是字符串中第一次和最后一次出现的 * 是相同的 * 的字符。因此,如果我们迭代字符串,并建立一些辅助数据结构,a)保持第一次/最后一次出现,b)允许其常数时间查找,我们可以在线性时间内解决任务。
那我们走吧:

def  first_non_repeating_letter(str) 
  # We'd like to have a hash where keys are chars (downcased)
  # and values are arrays of [<first occurence index>, <last occurence index>]
  positions = {}

  str.each_char.with_index do |c, i|
    key = c.downcase

    if positions.key?(key)
      # We've seen it before, so all we need to do is to update its last occurrence position
      positions[key][1] = i
    else
      # This is the 1st time we met the char `c`. So we make its first
      # and last occurrence positions the same (i) 
      positions[key] = [i, i]
    end
  end

  # At this point, for the given string 'sTreSS' (for example) we would build
  # positions = {"s"=>[0, 5], "t"=>[1, 1], "r"=>[2, 2], "e"=>[3, 3]}

  # Now let's do the main job finally
  str.chars.find { |c| positions[c.downcase][0] == positions[c.downcase][1] } || ""
end

pry(main)> first_non_repeating_letter('sTreSS')
=> "T"

相关问题