5月 29, 2024

Leetcode q3163 (Weekly 399). String Compression III

今天練習了上週 Weekly 399 的題目(很久沒週日起床了 ...),遇到了一題關於字串的操作,題目本身不難,可能有很高效的寫法,但我一樣用依照題目給的概念去解題,然後遇上了關於字串切割處理的問題

題目:3163. String Compression III

關於問題內容可以直接點進去參考,這邊只會簡述題目的需求跟這次表達的東西

題目需求很簡單,提供一組字串,然後由頭到尾掃描一次,當遇到不同字元時,將前一組字元的數量與字元合併串起,但若數量超過 9 時,則先切出 9 個後再重新計算長度

sample code

/**
 * @param {string} word
 * @return {string}
 */
var compressedString = function(word) {
    let comp = ""
    let tmpWord = ""
    let tmpCount = 0
    do {
        let fw = word[0]
        if((tmpWord != "" && fw != tmpWord) || tmpCount == 9) {
            comp += tmpCount + tmpWord
            tmpWord = fw
            tmpCount = 0
        }
        tmpWord = fw
        word = word.slice(1);
        tmpCount++
    } while(word.length>0)
    comp += tmpCount + tmpWord
    return comp;
};

在解這題時我遇到了 TLE ,原因是有一個相同文字的超長字串(大概就是 a*1000 個),而我把題目解決的方法也很簡單,就是改掉一個 function 而已。這個 function 就是 String.prototype.slice


原本使用的方法是 String.prototype.substring(indexStart, indexEnd),但我也沒有想到會差這麼多,儘管只跑贏 33%的解答,所以我就想知道到底這幾個差在哪邊




撇除使用方式不說,關於 javascript 切割字串最簡單常用的三個方法 substr(不建議使用) , substring , slice ,以找到的資料來看效率是 slice > substr > substring (也就是為什麼改成 slice 後就通過了)

接著就去找了這些方法在 Github 中的 source code 定義程式碼,分別如下

https://github.com/v8/v8/blob/daa0201ade9c1ffa7e0789b7150729270c75db6f/src/builtins/string-substr.tq

https://github.com/v8/v8/blob/daa0201ade9c1ffa7e0789b7150729270c75db6f/src/builtins/string-substring.tq

https://github.com/v8/v8/blob/daa0201ade9c1ffa7e0789b7150729270c75db6f/src/builtins/string-slice.tq

特別的是,扣除掉註解跟空白行後行數基本上一樣(而且 substr 還多了一行 const methodName 完全可以省略),而三個最後處理的共同方法都是使用同個 Substring(),所以就假設影響在中段的程式處理片段,而中間的差異,是兩個不同的方法 ConvertAndClampRelativeIndexClampToIndexRange ,覺得應該就是主要效率的影響

但看到這邊後再往這兩個方法的定義追查下去,發現其實好像沒有很明顯的差別.. 開始覺得放棄了,因為在 substring 跟 slice 的原始碼中,可能就只剩下一個差異是 substring 會多判斷參數的大小,如果開始大於結束,則會交換參數


if (end < start) {
      const tmp: uintptr = end;
      end = start;
      start = tmp;
    }


但 slice 其實也有這個判斷,只是差在 slice 會回傳空字串


if (end <= start) {
      return kEmptyString;
  }


但也就表示兩個方法都同樣有判斷(次數相同),所以到底還有什麼差異 ... 目前我是放棄去追尋了,先只能以結果來思考,如果條件允許就盡量用 slice 吧

沒有留言:

張貼留言