編寫乙個演算法來判斷乙個數n
是不是快樂數。
「快樂數」定義為:對於乙個正整數,每一次將該數替換為它每個位置上的數字的平方和,然後重複這個過程直到這個數變為1
,也可能是無限迴圈但始終變不到1
。如果可以變為1
,那麼這個數就是快樂數。
示例:
輸入:19
輸出:true
解釋:12+92
=8282+
22=6862+82
=10012+
02+02=
1
如果 n 是快樂數就返回true
;不是,則返回false
。
題意分析
先來分析一下題意,本題要求我們判斷乙個數是否為快樂數,就是將這個數的個位、十位、百位、千位……的平方和求出來判斷是否等於1,不等於的話進入下一次求和的過程。而某個數是否是快樂書的關鍵就是在對該數上的各位求平方和的時候不能陷入無限迴圈,而我們最直接的也最容易想到的方法就是將每一次求得的平方和儲存起來,每次求得乙個新的平方和的時候再對其進行查詢,判斷是否進入了死迴圈(即出現重複元素)。
hashset法
如果我們用最簡單陣列和鍊錶來儲存,那每次搜尋陣列的代價是o(n
)o(n)
o(n)
,這個代價太大了;仔細觀察一下,該儲存結構內儲存的元素是無序的、不重複的,並且要求最高的查詢效率。那我們應該馬上就想到用hashset
來儲存這些元素,因為它內部的元素是無序的,並且查詢效率為o(1
)o(1)
o(1)
。**:
//使用hashset檢測迴圈,再c++中是unordered_set
class
solution
return totalsum;
}//判斷是否是快樂數
bool
(int n)
return n ==1;
}};
上面只介紹了一種方法,並且這種方法是利用了內建資料結構的特性,所以並不能算作高明。
接下來的這兩種解法,才是最令人驚嘆的。
快慢指標法
接著上面的問題,如果乙個數是快樂數,那麼它必然是要退出迴圈並且最終等於1
的,如果它不是,那麼必然會進入乙個無限迴圈,所以我們在這裡引入乙個快慢指標的概念。快慢指標,顧名思義即有兩個指標一塊一慢,乙個在前面跑(步長大),乙個在後面趕(步長小),如果我們將無限迴圈看作乙個環(讀者不妨模擬一遍,它確實是乙個環),那麼快指標和慢指標總能相遇;而乙個數是快樂數的情況下,快指標總能最先到達1
。
**:
快慢指標法
class
solution
return totalsum;
}bool
(int n)
return fastrunner ==1;
}};
純數學方法
如果讀者聽我上面講的,對一定範圍內的數n進行模擬之後便會發現,這些數最後陷入的無限迴圈都是一樣的,即4
−>16−
>37−
>58−
>89−
>
145−
>42−
>20−
>
44->16->37->58->89->145->42->20->4
4−>16
−>37
−>58
−>89
−>14
5−>42
−>20
−>
4,根據這個規律,我們可以寫出非常簡潔的**,同樣要使用到hashset
來儲存這些無限迴圈數。
//數學方法1
class
solution
return totalsum;
}bool
(int n));
while
(n !=
1&& cyclemembers.
find
(n)== cyclemembers.
end())
return n ==1;
}};
進一步的,你也可以儲存所有這些無限迴圈數,你只需要儲存一位即可(例如4
)。
//數學方法2
class
solution
return totalsum;
}bool
(int n)
return n ==1;
}};
每日一題 LeetCode
在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數。示例 1 輸入 7,5,6,4 輸出 5 限制 0 陣列長度 50000 思想是 分治演算法 所有的 逆序對 於 3 個部分 左邊區間的逆序對 右邊區間的逆序對 橫跨兩個區間的...
LeetCode每日一題(題1028)
最近在刷leetcode每日一題,每次做完之後總能有些收穫,所以想著不如每天寫個部落格記錄一下做的題目的解法以及自己寫的時候問題出在 從先序遍歷還原二叉樹 題目大意 給出乙個字串 1 2 3 4 5 6 7 1代表節點的值,前面的 個數代表節點的深度。如果只有乙個子節點,保證這個節點為左子節點。返回...
LeetCode每日一題(題139)
題目 題目大意 給出乙個字串s和乙個字串陣列words,判斷s是否能夠拆分成多個words中的字串。分析 這道題比較簡單的方式應該是採用動態規劃來做。對於任意乙個字串中的區間,可以判斷該區間組成的字串是否在字典中,如果是,則這個區間的真假取決於前面那個區間的真假。給出狀態轉移方程dp i dp j ...