這是悅樂書的第188次更新,第190篇原創
01 看題和准備
今天介紹的是LeetCode算法題中Easy級別的第47題(順位題號是202)。編寫算法以確定數字是否“幸福”。
幸福數字是由以下過程定義的數字:從任何正整數開始,將數字替換為其數字的平方和,並重復該過程,直到最后數字等於1。這個過程以1結尾的那些數字是幸福的數字。如果陷入無限循環則不是幸福數字。例如:
輸入:19
輸出:true
說明:
1x1 + 9x9 = 82
8x8 + 2x2 = 68
6x6 + 8x8 = 100
1x1 + 0x0 + 0x0 = 1
本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。
02 第一種解法
從題目給的例子可以看出,每獲得一個新的數字,都需要按照個十百位拆分然后計算乘積,直到最后得到的是1為止,而那些不是幸福數字的數,會陷入死循環里面,因此,我們需要將每次新計算得到的結果保存起來,如果下次計算的時候遇到,可以直接判斷該數字不是幸福數字,因此我們使用HashMap來存值,使用遞歸來循環處理數據。因為需要多次使用Map,所以將其定義在方法外面,可以全局使用。
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
public boolean isHappy(int n) {
if (n <= 0) {
return false;
}
if (n == 1) {
return true;
}
int index = 1;
int sum = 0;
for (int i=0; i <(n+"").length(); i++) {
sum += Math.pow((n+"").charAt(i)-'0', 2);
}
if (sum == 1) {
return true;
}
if (map.containsKey(sum)) {
return false;
} else {
map.put(sum, index++);
}
return isHappy(sum);
}
03 第二種解法
思路與上面一樣,不過使用的是迭代的方法,所以,定義的HashMap放在你方法里面。使用了兩層循環,外層控制map判斷key是否存在以及替換新的n,內層循環處理新數不同位整數的平方和。
public boolean isHappy2(int n) {
if (n <= 0) {
return false;
}
if (n == 1) {
return true;
}
Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
int index = 1;
int sum = 0;
while (true) {
for (int i=0; i <(n+"").length(); i++) {
sum += Math.pow((n+"").charAt(i)-'0', 2);
}
if (sum == 1) {
return true;
}
if (map2.containsKey(sum)) {
return false;
} else {
map2.put(sum, index++);
}
n = sum;
sum = 0;
}
}
04 第三種解法
如果你算過幾個特殊的數,比如2、4、14、16、18,這些數字都會陷入死循環,並且是數字4.至於其他的數,如果不是幸福數,都會陷入死循環里面,死循環的入口就是4或者16,對此,我們可以不使用HashMap,只要判斷新得到的數是否等於4或者16即可表示此數字不是幸福數字。
此解法同樣是使用迭代的方法,借助兩層循環,外層做判斷,內層做不同位數字的平方和。
public boolean isHappy3(int n) {
int sum = 0;
while (sum != 1) {
if (n == 4 || n == 16)
break;
while (n > 0) {
int rem = n % 10;
sum += rem * rem;
n /= 10;
}
if (sum == 1)
return true;
n = sum;
sum = 0;
}
return false;
}
05 第四種解法
使用HashSet,借助其不能存在重復元素的特性,思路和第一、第二種解法一樣,都是先去獲取新數的平方和,然后添加進HashSet,如果添加失敗,說明已經存在該整數,即不是幸福數。不過這里是改變了n的原始值,所以最后判斷的是n是否等於1。
public boolean isHappy4(int n) {
HashSet<Integer> seen = new HashSet<>();
while (seen.add(n)) {
int square = 0;
int sum = 0;
while (n!=0) {
square = n%10;
sum += (square*square);
n /=10;
}
n = sum;
}
return n==1 ? true : false;
}
06 第五種解法
借助環的思路。如果你還對之前的判斷一個鏈表是否存在環的那道題目有印象的話,那么此題是與之類似的,每次新得到的數就代表一個節點,如果此節點出現過一次,即表示此鏈表是有環的,也就是說明此數是幸福數。
借助雙指針,一個每次進行一次計算,另外一個每次計算兩次,相當於速度是前一個的兩倍,如果存在相同的數,兩個指針肯定會相遇。
public boolean isHappy5(int n) {
int slow = n;
int fast = n;
do {
slow = digitSquareSum(slow);
fast = digitSquareSum(fast);
fast = digitSquareSum(fast);
if (slow == 1 || fast == 1) {
return true;
}
} while(slow != fast);
return false;
}
public int digitSquareSum(int n) {
int sum = 0, tmp;
while (n > 0) {
tmp = n % 10;
sum += tmp * tmp;
n /= 10;
}
return sum;
}
07 小結
算法專題目前已連續日更超過一個月,算法題文章47+篇,公眾號對話框回復【數據結構與算法】、【算法】、【數據結構】中的任一關鍵詞,獲取系列文章合集。
以上就是全部內容,如果大家有什么好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支持!