谁比谁长,回圈和 reduce 用法,Ruby 30 天刷题修行篇第十话

嗨~我是 A Fei,又到了我们愉快的解题时间,让我们马上来看看今天的题目:
(题目来源:Codewars


You are given an array(list) strarr of strings and an integer k. Your task is to return the first longest string consisting of k consecutive strings taken in the array.

Examples:

strarr = ["tree", "foling", "trashy", "blue", "abcdef", "uvwxyz"], k = 2

Concatenate the consecutive strings of strarr by 2, we get:

treefoling   (length 10)  concatenation of strarr[0] and strarr[1]
folingtrashy ("      12)  concatenation of strarr[1] and strarr[2]
trashyblue   ("      10)  concatenation of strarr[2] and strarr[3]
blueabcdef   ("      10)  concatenation of strarr[3] and strarr[4]
abcdefuvwxyz ("      12)  concatenation of strarr[4] and strarr[5]

Two strings are the longest: "folingtrashy" and "abcdefuvwxyz".
The first that came is "folingtrashy" so 
longest_consec(strarr, 2) should return "folingtrashy".

In the same way:
longest_consec(["zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"], 2) --> "abigailtheta"

n being the length of the string array, if n = 0 or k > n or k <= 0 return "".

Note
consecutive strings : follow one after another without an interruption


题目要我们将一个含有 n 个字串元素的阵列,依序以 k 个组成後,比较哪个字串比较长。如果一样长,就回传第一个值 ,此点非常重要,我当时看漏这个条件所以卡关超久...先贴我的答案:

def longest_consec(strarr, k)
  if strarr.length == 0 || k <= 0 || k > strarr.length
    ""
  else
    arr = []
    i = 0
    while i < (strarr.length - k) + 1
      arr[i] = strarr.slice(i, k).join("")
      i += 1
    end
    arr.reduce { |memo, word| memo.length >= word.length ? memo : word }
  end
end

题目很「贴心」地帮我们写出了例外条件「n being the length of the string array, if n = 0 or k > n or k <= 0 return ""」,我知道这样写很丑,但是为了赶时间直接在 if 判断中写死,好让我专心破解核心部分。

试着在脑海中模拟一下,假设有阵列 [1, 2, 3, 4],要依序取出 [1, 2]、[2, 3]、[3, 4],总共是要重复做三次事,也就是要跑 3 次回圈,所以「跑几圈」就是阵列长度 n 减去取出的元素个数 k,别忘了还要 + 1,写成 while 回圈就是:

while i < (strarr.length - k) + 1
 #do something 
  i += 1
end

接下来用 slice 方法,可以从原阵列中「切出」一部份,第一个参数是 index,第二个则是你要切的「长度」,这里就可以从 strarr[0] 开始,切出 k 长度的阵列,再用 join 组成字串,塞进空阵列 arr 里。

最後,就是用经典的 reduce 方法,两两比较 arr 中哪个字串比较长,「胜者」就留下来挑战下一个,直到最後「存活」下来那一个,就是最长的字串。但是题目有强调,如果碰到一样长的字串,留下来的是先出现的那个,也就是要写成 memo.length >= word.length ? memo : word 而非 memo.length > word.length ? memo : word,这就是我解题鬼打墙最久的地方。

比较评分最高的解法:

def longest_consec(strarr, k)
  return "" unless k.between?(1, strarr.length)
  strarr.each_cons(k).map(&:join).max_by(&:length) || ""
end

Wow,第一行就用了我没看过的 between? 方法,不过字面上的意义很好懂,这里就不深入分析了。而下一行也是让人眼花撩乱,有两个没看过的方法,大哥你是把整本手册都背起来了吗?只能先查一下手册

1.each_cons 方法,带入 a,就可以从 Enumerable 迭代取出长度为 a 的值,简直是为这题量身打造,直接看官网范例:

(1..10).each_cons(3) { |a| p a }
# outputs below
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 10]

如果後面没有接 {} 的话,它会回传一个枚举器 enumerator。

  1. &: 写法,还原就是 map{|el| el.join("")} ,这部分可以等日後再谈。
  2. max_by,返回 Enumerable 中最大值,这里是 length。

好啦,这次的解题纪录就先到这,最近比较忙没什麽时间喇赛想梗,希望之後能多一点时间写文,掰掰啦


<<:  Day-10 回圈

>>:  Day 24:程序「动」起来

[Day11] 文本/词表示方式(二)-BOW与TFIDF

一. BOW BOW的全名为Bag-of-words,中文是'一袋文字',意思就是将词都丢进一个袋子...

《赖田捕手:追加篇》第 34 天:妥善运用 LINE Notify 免费推播

第 34 天:妥善运用 LINE Notify 免费推播 「恩...我是在想你今天晚上要不要用pus...

Day 08 Create a classification model with Azure Machine Learning designer

Classification - Predict category or class Train r...

[Day 11] 实作 Ktor i18n 机制

以微框架来说,i18n 不是必备的功能,但如果是想要开发面向一般大众的服务,在这个国际化的时代,i1...

[心得]资料异动行为,需要有意识的风险管理

纪录一下最近遇到的问题 一支异动订单的API ,称作 Patch Order,在一秒内被打了两次,造...