回文计数字符串

时间:2013-11-20 18:51:16

标签: ruby string algorithm palindrome

所以,我今天探索了www.hackerearth.com并在ruby中解决了我的第一个问题陈述:http://www.hackerearth.com/problem/algorithm/palindrome-count-1/

回文数问题

给定一个字符串S,计算作为回文的非空子字符串的数量。 子字符串是字符串中任何连续的字符序列。 如果字符串的反向与自身相同,则称字符串为回文。 如果它们出现在S

中的不同位置,则两个子字符串是不同的

输入:输入只包含一行包含字符串S的行。

输出:打印单个数字,即回文子字符串的数量。

约束

1< = | S | < = 50

S仅包含小写拉丁字母,即字符a到z。

示例输入(明文链接):dskjkd
示例输出(明文链接):7

说明 -

7个子字符串是d,s,k,j,k,d,kjk。

时限3秒(s)

内存限制256 MB

来源限制1024 KB

以下是我的所作所为:

chars = gets.chomp.gsub(' ', '').split('')
counts = chars.count
(2..chars.count).each do |len|
  chars.combination(len).each do |comb|
    string = comb.inject(:<<)
    counts += 1 if string.reverse == string
  end
end
puts counts

然而,就时间执行和内存使用而言,这种方法似乎效率低下。有没有办法优化这个?或者对此解决方案有任何其他方法,也欢迎算法作为解决方案!感谢。

修改

因为,所有答案都是正确的。我必须选择一个有效的。所以,我运行了基准测试,结果如下:https://gist.github.com/suryart/7577481

根据结果,您可以看到this answer更快。感谢您的新方法/解决方案! :)

3 个答案:

答案 0 :(得分:2)

这种方法 - 伪代码 - 应该可行。

input: String s

// each single letter is palindrome itself
palindromsCount = length(s)

// let count all odd-length palindromes first (palindrome of length 1 already counted)
// we will be checking from the very middle of a sub-string, if it is symmetric 
for(int i = 1; i < length(s)-1; i++)
   for(int j = 1; ; j++)
       if (i - j < 0 || i + j >= length(s) || s[i-j] != s[i+j])
          break
       else
          palindromsCount += 1

// let count in similar way all even-length palindromes
for(int i = 0; i < length(s)-1; i++)
   for(int j = 0; ; j++)
       if (i - j < 0 || i + j + 1 >= length(s) || s[i-j] != s[i+j+1])
          break
       else
          palindromsCount += 1

编辑当然,这两个循环可以组合成一个循环 - 我不想这样做是为了提高可读性。

答案 1 :(得分:1)

使用该算法从What is the best way to split a string to get all the substrings by Ruby?

获取字符串的所有子集
count = 0

(0..len-1).each do |i|
  (i..len-1).each do |j|
    temp = s[i..j]
    count = count + 1 if temp == temp.reverse
  end
end
puts "found #{count} palindromes"

答案 2 :(得分:1)

Enumerable#each_cons在这里很方便:

str = "momanddadpaddledthekayak"

b = str.chars
(1..b.size).reduce(0) {|t,n| t + b.each_cons(n).reduce(0) \
  {|r,e| w = e.join; w==w.reverse ? r + 1 : r}} # => 30

如果我们想看到苍白的景象:

b = str.chars
pals = (1..b.size).each_with_object([]) {|n, a| b.each_cons(n).each \
  {|e| w = e.join; a << w if w==w.reverse}}

p pals.size # => 30
p pals #  => ["m", "o", "m", "a", "n", "d", "d", "a", "d", "p", "a",\
              "d", "d", "l", "e", "d", "t", "h", "e", "k", "a", "y",
              "a", "k", "dd", "dd", "mom", "dad", "aya", "kayak"] 

编辑:@squiguy做了有用的观察,我们可能不想计算重复数。如果是这种情况,我上面的第一个计算就无法使用,第二个计算必须改变为squiguy暗示(例如p a.uniq.size)或更改为构建散列而不是数组:

b = str.chars
pals = (1..b.size).each_with_object({}) {|n,h| b.each_cons(n).each \
  {|e| w = e.join; h[w] = 0 if w==w.reverse}}.keys

p pals.size # => 17
p pals# => ["m", "o", "a", "n", "d", "p", "l", "e", "t",\
            "h", "k", "y", "dd", "mom", "dad", "aya", "kayak"] 

[修改:将each替换为each_with_object。在重读这个问题时,似乎要计算重复数。]