[寶寶也能看懂的活動篇][30-Day LeetCoding Challenge] 次日

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

這是一個 leetcode 官方的小活動。能夠在官網看到,從 4 月 1 號開始,天天官方會選出一道題,在 24 小時內完成便可得到一點小獎勵。雖然獎勵彷佛也沒什麼用,不過做爲一個官方的打卡活動,小豬仍是來打一下卡吧,正好做爲天天下班回家後的娛樂。github

這裏是 4 月 2 號的題,也是題目列表中的第 202 題 -- 『快樂數』算法

題目描述

編寫一個算法來判斷一個數是否是「快樂數」。shell

一個「快樂數」定義爲:對於一個正整數,每一次將該數替換爲它每一個位置上的數字的平方和,而後重複這個過程直到這個數變爲 1,也多是無限循環但始終變不到 1。若是能夠變爲 1,那麼這個數就是快樂數。segmentfault

示例 1:數據結構

輸入: 19
輸出: true
解釋:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

官方難度

EASYapp

解決思路

題目的內容很是直白,讀完題目以後小豬的第一反應也很直接,那就是咱們須要根據一個數,找到符合題目要求的下一個數。即咱們須要拿到這個十進制數的每一位數字,而後將它們的平方求和。函數

這個過程並不複雜,因此小豬這裏就不賣關子啦,直接給出相關的函數實現:spa

const next = n => {
  let ret = 0;
  while (n !== 0) {
    ret += (n % 10) ** 2;
    n = (n / 10) >> 0;
  }
  return ret;
}

這裏面惟一一個須要注意的地方,可能就是這個看起來很奇怪的右移 0 位的操做。小豬這裏只是用它來實現一個數字的取整。固然咱們也能夠用任何其它的取整方式來替換。指針

如今咱們已經能夠根據一個數找到符合要求的下一個數啦,那麼如何判斷它到底是不是快樂呢?咱們能夠先想一下,判斷快樂數的退出條件是什麼。若是當獲得 1,那麼會觸發成功的退出條件;若是當咱們不斷運算的過程當中,發現獲得了一個曾經出現過的數字,那麼意味着這個過程會持續的循環下去,因而這時候應該觸發失敗的退出條件。

基於這個思路,下面給出 3 種方案,供小夥伴們參考。

方案 1

這是個很直接的方案,咱們能夠經過一個集合來保存已經出現過的數字。這樣對於每個計算結果,咱們只須要看它是否存在於集合中便可。若是存在,則觸發失敗退出;若是不存在,則添加進集合,並繼續計算,直到咱們獲得了 1 爲止。

這個方案是很是容易想到的,不過缺點是咱們須要額外的空間來記錄整個歷史集合。具體代碼以下:

const isHappy = (n) => {
  const history = new Set([n]);
  while (n !== 1) {
    n = next(n);
    if (history.has(n)) return false
    history.add(n);
  }
  return true;
}

方案 2

咱們從新回看整個計算過程,從數字 N1 計算出下一個數字 N2,再計算出更下一個數字 N3,直到咱們獲得了 1 或者一個出現過的 Nx。這個過程連起來像不像是一種叫作鏈表的數據結構?而失敗的條件正好就是鏈表包含環。因此這個問題能夠直接套用判斷鏈表是否包含環的思路來處理。

那麼,處理這類問題,咱們有一種經典的不須要額外空間的方式,那就是快慢指針。過程大概就是,維護一個一次移動一步的慢指針,和一個一次移動兩步的快指針。若是包含環,那麼快指針必定會在一個時刻實現對慢指針的套圈。

再返回這道題目,因爲咱們獲得 1 之後,不管再怎麼繼續計算,結果始終是 1 。因此咱們須要作的就是完成這個套圈時機的計算。最終再根據套圈後指針的值來判斷到底是由於 1 套圈,仍是由於成環套圈便可。具體代碼以下:

const isHappy = n => {
  let slow = n;
  let fast = next(n);
  while (slow !== fast) {
    slow = next(slow);
    fast = next(next(fast));
  }
  return slow === 1;
}

方案 3

這個方案是一個比較偏數學的方案。簡單的說就是,咱們能夠嘗試羅列 1-9 這幾個數字它們會產生的後續狀況,最終會發現其實它們要麼會成爲快樂數,要麼都會歸結爲固定的循環。而那些多餘 1 位的數,最終也會變成某個覺得的數字從而歸結到這兩種狀況上來。因此咱們只須要對這些特殊狀況作判斷便可。

這裏若是感興趣的小夥伴,能夠直接去 wikipedia 搜索『Happy number』,即會看到詳細的分析過程。

那出於對於傳統文化的尊重(大霧),咱們這裏判斷一個特殊狀況,即若是這個數字不快樂,那麼它必定會途徑 4 這個特殊值(畢竟是個彷佛很不吉利的數字)。基於此,咱們能夠直接獲得下面這個簡單的實現:

const isHappy = (n) => {
  while (n !== 1 && n !== 4) n = next(n);
  return n === 1;
}

總結

做爲『30-Day LeetCoding Challenge』的第二題,仍舊是這麼的和善可親。小豬嘗試給出了 3 種徹底不一樣的思路,但願能幫到有須要的小夥伴。

不太小豬也十分好奇,MEDIUM 或者 HARD 難度的題何時會出現?下注下注,買定離手啦~

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

相關連接

qrcode_green.jpeg

相關文章
相關標籤/搜索