iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0
自我挑戰組

從真「新」鎮出發!30天的刷題修行篇,讓寫程式成為新必殺技系列 第 10

誰比誰長,迴圈和 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。

好啦,這次的解題紀錄就先到這,最近比較忙沒什麼時間喇賽想梗,希望之後能多一點時間寫文,掰掰啦


上一篇
Two Sum 演算法初階題,Ruby 30 天刷題修行篇第九話
下一篇
輕鬆排序!sort 的延伸用法,Ruby 30 天刷題修行篇第十一話
系列文
從真「新」鎮出發!30天的刷題修行篇,讓寫程式成為新必殺技16

尚未有邦友留言

立即登入留言