0x01.問題
編寫一個算法來判斷一個數 n 是不是快樂數。
「快樂數」定義爲:對於一個正整數,每一次將該數替換爲它每個位置上的數字的平方和,然後重複這個過程直到這個數變爲 1,也可能是 無限循環 但始終變不到 1。如果 可以變爲 1,那麼這個數就是快樂數。
如果 n
是快樂數就返回 True
;不是,則返回 False
。
示例:
輸入:19
輸出:true
解釋:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2= 1
public boolean isHappy(int n)
0x02.解決思路
讀題,發現題目要點:
- 判斷一個數,經過一系列【每一次將該數替換爲它每個位置上的數字的平方和】操作,是否可以變成1。
問題其實很簡單,只需要不斷的模擬這個過程變換就可以了,但是,在裏面會存在一些問題。
如果它永遠不會變成1,那麼它會怎樣變換呢?
一種想法是,它會越來越大,越來越大,最後會超出整型的範圍,但是我們可以拿個具體的例子看一下。
-
三位數經過這個操作能得到的最大的數字是999—>243,四位數是9999—>324。
-
再來看一下接近整型的大數9999999999999—>1053。
我們發現,其實並不會大到超出整型的範圍,而是會在一個很小的範圍內變換
,那麼在這個小範圍的變換就只有兩種情況了。
- 最後變成1。
- 不斷循環。
第一種情況是我們需要的,我們只需要判斷是否出現循環就行了,如果出現了循環,並且還沒有得到1,說明之後是不可能再得到1了的。
如何判斷是否出現循環了呢?很簡單,只需要判斷當次得到的數是否已經出現過就行了。那麼我們可以使用一個哈希表存儲一下每次得到的數,如果當次得到的數已經出現過了,那麼直接返回false
。
class Solution {
private int next(int n){
int ans=0;
while(n>0){
int d=n%10;
n/=10;
ans+=d*d;
}
return ans;
}
public boolean isHappy(int n) {
Set<Integer> hash=new HashSet<>();
while(n!=1&&!hash.contains(n)){
hash.add(n);
n=next(n);
}
return n==1;
}
}
這種方法是最簡單,最直接的。
其實,判斷是否出現循環,還有另外一種常用的方法,快慢指針,跟判斷鏈表是否成環思路一樣。
0x03.解決代碼–快慢指針
class Solution {
private int next(int n){
int ans=0;
while(n>0){
int d=n%10;
n/=10;
ans+=d*d;
}
return ans;
}
public boolean isHappy(int n) {
int slow=n;
int fast=next(n);
while(fast!=1&&fast!=slow){
slow=next(slow);
fast=next(next(fast));
}
return fast==1;
}
}
ATFWUS --Writing By 2020–04-30