

判断链表有环?
我们在学习链表的时候,讲过如何判断链表是否有环的办法,讲解的时候是用的双指针的办法,如果有环,就会在这个环里相遇
算法步骤:
数学原理: 设链表头到环入口的距离为a,环入口到相遇点的距离为b,相遇点到环入口的距离为c。 则环的长度为b+c。 当slow和fast相遇时,slow走过的距离为a+b,fast走过的距离为a+b+n*(b+c),其中n是fast在环中绕的圈数。 因为fast的速度是slow的两倍,所以有:2(a+b) = a+b + n*(b+c) => a = (n-1)*(b+c) + c 这个公式说明,从链表头到环入口的距离a等于从相遇点到环入口的距离c加上n-1圈环的长度。 因此,当两个指针分别从链表头和相遇点以相同速度前进时,它们会在环入口处相遇。
a:链表头到环入口的距离
b:环入口到相遇点的距离
c:相遇点到环入口的距离(顺时针方向)
n:快指针在相遇前在环中走的圈数
L:环的长度 = b + c
头 → 入口 → 相遇点 → 入口(完成环)
慢指针路程:a + b
快指针路程:a + b + n × L
(因为快指针可能已经在环里转了n圈)
由于快指针速度是慢指针的2倍:
2 × (a + b) = a + b + n × L
化简得:
a + b = n × L
a = n × L - b
a = (n - 1) × L + (L - b)
a = (n - 1) × L + c第一种方法:
text
序列:n → ... → 1 → 1 → 1 → ...
特点:1的平方和还是1,所以1是一个自循环
快慢指针轨迹:
慢指针:会慢慢走向1
快指针:会更快到达1
最终,它们会在1相遇text
序列:n → ... → 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 → ...
特点:进入一个不包含1的循环
快慢指针轨迹:
慢指针:在循环中前进
快指针:在循环中更快前进
最终,它们会在循环中的某个点相遇(比如4或16等),但绝对不是1class Solution {
public int sumOfSquares(int n) {
int sum = 0;
while (n > 0) {
int digit = n % 10;
sum += digit * digit;
n /= 10;
}
return sum;
}
public boolean isHappy(int n) {
int slow = n;
int fast = sumOfSquares(n);
while(slow != fast){
slow = sumOfSquares(slow);
fast = sumOfSquares(sumOfSquares(fast));
}
return slow == 1;
}
}鸽巢原理(抽屉原理):

这个题有一个n 得取值范围:

我们直接换算成最大得

我们就简单得先计算多少位,是十位数,也就是2^10得九次方,那不如我们直接写成最大值以9来计算,十个9
10个9 进行每一位的平方和是810,也就是我们最大的值都小于十个9,所以我们进行的每一位平方和相加肯定也小于810
【1,810】就是我们的巢穴,我们接下来找鸽子,我们的巢穴是1-810
我们肯定超过这个810就会出现重复的的,也就是我们所说的进入环了
方法三:
text
定理:对于函数 f,从任意 n 出发的序列要么:
1. 收敛到不动点 1
2. 进入一个不包含 1 的循环
证明:
假设存在一个包含 1 的循环,但不是 {1}。
那么循环中必有一个数 a ≠ 1,但 f(a) = 1。
但 f(a) = 1 意味着 a 的各位平方和为 1。
满足这个条件的 a 只能是:1, 10, 100, 1000, ...
计算这些数的平方和:
1 → 1
10 → 1
100 → 1
1000 → 1
...
这些数最终都会进入 1→1 的自循环。
因此,任何包含 1 的循环只能是 {1}。想象这样的序列:
... → x → 1 → y → ... → x → ...
从 1 开始:1 → f(1) = 1,不可能得到 y ≠ 1
所以一旦到达 1,就永远卡在 1 了class Solution {
public int sumOfSquares(int n) {
int sum = 0;
while (n > 0) {
int digit = n % 10;
sum += digit * digit;
n /= 10;
}
return sum;
}
public boolean isHappy(int n) {
Set<Integer> seen = new HashSet<>();
while (n != 1) {
n = sumOfSquares(n);
if (seen.contains(n)) {
return false;
}
seen.add(n);
}
return true;
}
}