[寶寶也能看懂的活動篇][30-Day LeetCoding Challenge] 第十二天

最後一塊石頭的重量

Hi 你們好,我是張小豬。歡迎來到『寶寶也能看懂』系列特別篇 - 官方小活動 『30-Day LeetCoding Challenge』。git

這裏是 4 月 12 號的題,也是題目列表中的第 1046 題 -- 『最後一塊石頭的重量』github

題目描述

有一堆石頭,每塊石頭的重量都是正整數。shell

每一回合,從中選出兩塊 最重的 石頭,而後將它們一塊兒粉碎。假設石頭的重量分別爲 x 和 y,且 x <= y。那麼粉碎的可能結果以下:segmentfault

  • 若是 x == y,那麼兩塊石頭都會被徹底粉碎;
  • 若是 x != y,那麼重量爲 x 的石頭將會徹底粉碎,而重量爲 y 的石頭新重量爲 y-x

最後,最多隻會剩下一塊石頭。返回此石頭的重量。若是沒有石頭剩下,就返回 0數組

示例:優化

輸入:[2,7,4,1,8,1]
輸出:1
解釋:
先選出 7 和 8,獲得 1,因此數組轉換爲 [2,4,1,1,1],
再選出 2 和 4,獲得 2,因此數組轉換爲 [2,1,1,1],
接着是 2 和 1,獲得 1,因此數組轉換爲 [1,1,1],
最後選出 1 和 1,獲得 0,最終數組轉換爲 [1],這就是最後剩下那塊石頭的重量。

提示:spa

  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 1000

官方難度

EASYcode

解決思路

看起來描述挺長,但其實就是一個大值依次互相抵消求最後剩餘的小遊戲。小豬沒有想到什麼數學方式,因此就正常的根據遊戲流程來求最終結果吧。blog

直接方案

因爲數字是無序的,因此咱們先進行一個排序。而後按照遊戲流程,把兩個最大值進行抵消,若是存在餘量則經過插入排序的方式放入合適的位置。這樣直到最後剩餘 0 個或者 1 個數字,便獲得告終果。排序

具體代碼以下:

const lastStoneWeight = stones => {
  stones.sort((a, b) => a - b);
  while (stones.length > 1) {
    const x = stones.pop();
    const y = stones.pop();
    if (x === y) continue;
    const d = Math.abs(x - y);
    let idx = stones.length;
    while (idx > 0) {
      if (stones[idx - 1] <= d) break;
      stones[idx] = stones[idx - 1];
      --idx;
    }
    stones[idx] = d;
  }
  return stones.length === 1 ? stones[0] : 0;
};

優化

上面的方案最開始使用了一個全局的排序,隨後在遍歷中也對餘量使用了一次基於遍歷的插入行爲。那麼這裏優化方案很是明顯,咱們能夠優化排序的方式,從而簡化整個流程。

因爲輸入數據的範圍是 [1, 1000],因此咱們能夠很是輕鬆的用桶排序來完成最初的排序,而且後續的餘量處理也會變得更加容易。具體代碼以下:

const lastStoneWeight = stones => {
  const buckets = new Uint8Array(1001);
  let t = 0;
  for (const val of stones) ++buckets[val];
  for (let i = 1000; i > 0; --i) {
    if (!buckets[i]) continue;
    if (!t) { buckets[i] % 2 && (t = i); continue; }
    const d = Math.abs(t - i);
    t = d >= i ? d : (++buckets[d], 0);
    --buckets[i++];
  }
  return t;
};

總結

又是一個基於桶排序完成的優化,在特定的場景下仍是『真香』的。但願能幫助到有須要的小夥伴。

若是以爲不錯的話,記得『三連』哦。小豬愛大家喲~

相關連接

qrcode_green.jpeg

相關文章
相關標籤/搜索