思路: 环形链表那一套
最终只会出现两种情况:
- 重复多次后平方和变为1
- 无限进行下去,出现重复的循环。
为何平方和不会越来越大?
如果当n越来越大的时候,n的每一位数字的平方和总小于n,则说明n不会越来越大。
证明:
方法2:用快慢指针判断。时间复杂度O(n),空间复杂度O(1)
-
快慢指针一定在环内相遇,
- 原因:快指针会在圈内一直绕,当慢指针进入圈后,快指针会追赶慢指针,直到套圈。并且慢指针最多走完一个圈的距离。
-
慢指针肯定不会走多圈,会在一圈之内被追上。
- 假设fast在slow前x个单位,假设环长度为L, fast需要追赶L-x长度,追赶的速度为2-1=1,追赶上所花费的时间为L-x/1 = L-x。在这段时间内,slow走的距离为 1 * (L-x) = L - x, 永远小于L,因此slow不可能走完一整个环。
class Solution {
public boolean isHappy(int n) {
int slow = n, fast = n;
while (fast != 1 && sqrSum(fast) != 1) {//因为fast一次跳两步
slow = sqrSum(slow);
fast = sqrSum(sqrSum(fast));
if (fast == slow) {//如果快慢指针相遇,则出现了循环
return false;
}
}
return true;
}
//求n的每一位数字构成的平方和
public int sqrSum(int n) {
int sum = 0;
while (n != 0) {
sum = sum + (int)Math.pow(n % 10, 2);
n = n / 10;
}
return sum;
}
}
Find entrance of loop: Let’s say:
L
= distance from head to loop startC
= cycle lengthx
= distance from loop start to meeting point
At the meeting point:
fast
has traveledL + nC + x
slow
has traveledL + x
- Since
fast
moves twice as fast:
2(L + x) = L + nC + x
Simplifies to:L = nC - x
class Solution {
public boolean isHappy(int n) {
int slow = n, fast = n;
// Step 1: Detect cycle
while (fast != 1 && sqrSum(fast) != 1) {
slow = sqrSum(slow);
fast = sqrSum(sqrSum(fast));
if (slow == fast) {
// Step 2: Find entrance to the cycle
int entry = n;
while (entry != slow) {
entry = sqrSum(entry);
slow = sqrSum(slow);
}
System.out.println("Loop starts at: " + entry);
return false; // There's a loop, and 1 is not reachable
}
}
return true; // fast == 1 or its next step is 1 → happy number
}
public int sqrSum(int n) {
int sum = 0;
while (n != 0) {
sum += (int)Math.pow(n % 10, 2);
n = n / 10;
}
return sum;
}
}
方法1:用set记录出现过的数字。时间复杂度O(n),空间复杂度O(n)
class Solution {
public boolean isHappy(int n) {
Set<Integer> set = new HashSet<>();
set.add(n);
while (sqrSum(n) != 1) {
if (set.contains(sqrSum(n))) {
return false;
}
n = sqrSum(n);
set.add(n);
}
return true;
}
//求n的每一位数字组成的平方和
public int sqrSum(int n) {
int sum = 0;
while (n != 0) {
sum = sum + (int)Math.pow(n % 10,2);
n = n / 10;
}
return sum;
}
}