Common fast and slow pointer question types
1. Find the middle node of the linked list
Double pointer advanced solution
1. Define two pointers, one fast pointer and one slow pointer.
2. The fast pointer takes two steps at a time, and the slow pointer takes one step at a time.
3. When considering where the fast pointer points to, our slow pointer just reaches the middle node
Use two pointers slow
and fast
to traverse the linked list. slow
Take one step at a time, fast
two steps at a time. Then when fast
it reaches the end of the linked list, slow
it must be in the middle.
1. Define the fast and slow pointers
2. The fast pointer takes one step at a time, and the slow pointer takes two steps at a time
3. Exit the loop when the fast pointer isnull
or the fast pointernext为null
The premise mentioned that if there are two intermediate nodes, the second intermediate node will be returned, so let's see if this solution is suitable for an even number of nodes
Looking at the picture, we can know that no matter whether the linked list is odd or even, it will not affect the final result.
Judgment condition:
At that timefast==null
, orfast.next==null
when, exit the loop.
Note : Since the logical operator && judges the left side first, and then judges the right side when the left side is true, if mine isfast
already truenull
, then if Ifast.next
write it on the left side, a null pointer exception will occur, so we need to judge fast first Is itnull
, that is, it will befast!=null
written on the left
code show as below
class Solution {
public ListNode middleNode(ListNode head) {
//定义两个指针,一个快指针,一个慢指针
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;//慢指针一次走一步
fast = fast.next.next;//快指针一次走两步
}
return slow;//返回慢指针
}
}
Complexity analysis:
- Time complexity O(n) , where
N
is the number of nodes in the given linked list. - Space complexity O(1) , only need constant space to store two pointers of slow and fast.
2. Find the Kth node from the bottom
Problem-solving ideas:
Define a fast and slow pointer, let the fast pointer go K steps first, and then the slow pointer and the fast pointer go together. When the fast pointer is null, our slow pointer is the Kth number from the bottom.
How did the above reasoning come about?
Let's see the picture demo
Step 1: Let the fast pointer cur take K steps, as shown in Figure 2. Step
2: The fast pointer and the slow pointer move together, and exit the loop when the fast pointer is null
Step 3: At this time, prev is the Kth node from the bottom , just return to prev
The specific process is as follows
Using the fast and slow pointers as shown in the figure, first let the fast pointer go k steps first, and then let the fast and slow pointers walk one step at a time until the fast pointer points to an empty node, and the slow pointer is the kth node from the bottom
Enter the code and
pay attention to the comments! ! !
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
//判断链表是不是为空,并且k不能小于等于0
if (k<=0||head==null) {
return null;
}
int n=0;
ListNode prev=head;
ListNode cur=head;
while (n<k) {
//判断cur是否为null
//如果为null返回null
if (cur==null) {
return null;
}
cur=cur.next;
n++;
//如果将if放到下面,
//那么判断倒数第n个结点时就会出错,n是链表长度,
//也就是查找链表头节点时会报错
//if (cur==null) {
// return null;
// }
}
while (cur!=null) {
prev=prev.next;
cur=cur.next;
}
return prev;
}
}
Author's summary:
There is an extreme condition that when the penultimate K-th node is the head node, the if cannot be placed in the position I commented in the code, as shown in the figure below
If you exit
cur == null
at the time of , then there is a situationcur==null
that when mine, my prev is the penultimate 5th node that meets the conditions. If you exit at this time, the result will be different from the expected result, so we will judge The condition is written above, in that case, only when our n does not meet the conditioncur==null
, it returns null, thus avoiding the above error
Input a linked list, output the penultimate k-th node oj in the linked list
3. Judging the circular linked list
Title description:
Give you a linked list, judge whether it has a ring, if it has a ring, return
true
otherwise returnfalse
Fast and slow pointer solution :
Suppose classmate "A" and classmate "B" met to run together, and they came out of the dormitory building together, because "A" ran fast, so "A" arrived at the playground first to run laps, if it is not a lap (no ring), then "B" will never catch up with "A". When "B" enters the playground, because "A" is fast, it will definitely meet "B" at a certain moment, that is, run more than "B". several laps.
We can use the above ideas to solve this problem:
1. Set a fast and slow pointer
2. The fast pointer takes two steps at a time, and the slow pointer takes one step at a time.
3. When the fast pointer is empty or the next node of the fast pointer is empty, exit the loop (this means there is no ring) and return tofalse
4. When the slow pointer catches up with the fast pointer, it means that there is a ring and returntrue
Let's look at the picture below:
The code is as follows :
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode A=head;//快指针
ListNode B=head;//慢指针
while(A!=null&&A.next!=null) {
A=A.next.next;//快指针一次走两步
B=B.next;//慢指针一次走一步
//当两个结点相同时,意思就是相遇了
if(A==B) {
return true;//返回正确
}
}
return false;//当出了循环说明这个链表没有环,返回错误
}
}
Complexity Analysis
Time Complexity: O(N)O(N)O(N), where NNN is the number of nodes in the linked list.
Space complexity: O(1)O(1)O(1). We only use an additional space
complexity analysis of two pointers:
- Time complexity O(n), where
N
is the number of nodes in the given linked list.
When there is no ring in the linked list, the fast pointer will reach the end of the linked list before the slow pointer, and each node in the linked list is visited twice at most.
When there is a ring in the linked list, after each round of movement, the distance between the fast and slow pointers will decrease by one. The initial distance is the length of the ring, and because the slow pointer moves at most N times, it moves at most N rounds. (explained below)
- Space complexity O(1), only two pointers are used for extra space
Why does the slow pointer move at most N times ? (N is the length of the linked list)
We can imagine that two people are running. Since "A" runs fast, they will definitely meet "B". The premise is mentioned above. The speed of "A" is twice that of "B". So when student "B" runs one lap, student "A" must have completed two laps (the starting point of A is calculated from the current position of student A when B enters the playground), so no matter what, they will definitely meet ,
Why does the fast pointer have to be two steps at a time, if it is three steps at a time, can it be four steps at a time ?
Example :
The answer is no! Maybe in mathematics, you can calculate the time of meeting or the number of times you move when meeting (that is because there are decimals in mathematics), but the linked list is different. Every step of it is an integer, and there is no such thing as decimals. Like flying chess when I was young, if there is a treasure box one grid away from you, then you will not get the treasure box if you take four steps, three steps, or even two steps, and you can only watch and rub it against it. Passing by, just like you are trying to create a chance to meet your goddess, she goes out at three o'clock, how about you? Go downstairs to her dormitory at 3:01, then you will never meet, this is a miss, and you can't miss a single cent. Therefore, in the process of catching up with love, we should grasp the timing and would rather come early than late. Maybe you don’t know when she will come back, but you have to be prepared, even if you come six hours early, even if it’s snowy, even if you stand Don't give up even if you are frozen into a popsicle by only wearing a thin coat for the sake of being cool on the street, all these sacrifices will be worth it when you are with her in the end! (The story comes from a certain Song teacher at station B, ahem, a bit off topic)
back to business
If you take three steps at a time:
There is an extreme situation, if your ring is an odd number, then the distance between you and him (3-1=2) is shortened by two steps each time, no matter how many even numbers are subtracted from an odd number, it is still an odd number, and you will not meet, there is just endless misses
If four steps at a time:
If the ring is an even number, then the distance between you and it is shortened by three distances each time (4-1=3). No matter how many times you subtract, he will never meet.
If you take two steps each time:
Regardless of odd or even numbers, since I take two steps each time, our direct distance is shortened by one step each time (2-1=1), all integers are multiples of 1, and we will meet eventually!
4. Find the entry of the ring list (advanced)
Topic: Determine whether it is a circular linked list, if the linked list has a ring, return the first node that enters the ring.
Fast and slow pointer solution :
This actually involves the knowledge of mathematics, we are still drawing examples.
We can think of L
it as the length when not entering the ring at this time, X
and the length of is the distance from the first node entering the ring until the fast and slow pointers intersect. C
is the remaining length in the loop.
The slow pointer moves one step at a time, and the fast pointer moves two steps at a time
So we can deduce
The length of the slow pointer: L+x
The length of the fast pointer: L+x+k(x+c)
x+c=circumference of the ring
Because there may be a situation where the ring is very short or L
very long. If this is the case, then the fast pointer needs to walk the ring many times , so it is k(x+c)
.
It can be calculated by the above formula:
Since the speed of the fast pointer is twice that of the slow pointer, when the slow pointer × 2 is the distance traveled by the fast pointer
2(L+x)=L+k(x+c)+x
//The following is to remove the brackets, shift items, and merge the same type
L+x=x+c+(k-1)(x+c)
L=c+ (k-1)(x+c)
L-(k-1)(x+c)=c
We assume two nodes A and B as shown in the figure
No matter how many (x+c) my A pointer has moved, the position of my A pointer has not changed, but my B pointer has moved forward (k-1)(x+c) positions, so when After walking (k-1)(x+c), our B is only c nodes away from the ring entrance, and because our A pointer is also c nodes away from the ring entrance, so the position where they intersect is Entrance to the ring.
We can't judge how many of these variables are, but we can find the correct answer by looking for their direct relationship!
The picture is as follows:
Step 1: Find the intersection point
Step 2: Two pointers, one from the head variable and one from the intersection node
code show as below:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode A=head;//慢指针
ListNode B=head;//快指针
//找到交点
while(B!=null&&B.next!=null) {
//①
B=B.next.next;
A=A.next;
//切记不可以写在①那个位置
if(A==B) {
break;
}
}
//判断因为什么退出循环
//如果是因为结点为空,则直接返回null
if(B==null||B.next==null) {
return null;
}
//
B=head;//B指针是头节点的位置
//相交时,他们的交点就是环的入口结点
while(A!=B) {
A=A.next;
B=B.next;
}
//返回A,B都行
return A;
}
}
Notice:
As mentioned in the comments,
if()
it cannot be written in the position of ①, because they are the same at the beginning. If they are written together, then it will directly exit the loop! ! !
Complexity analysis:
-
Time complexity : O(N), where N is the number of nodes in the linked list. When initially judging whether the fast and slow pointers meet,
prev
the distance traveled by the pointer will not exceed the total length of the linked list; when looking for the loop-entry point, the distance traveled will not exceed the total length of the linked list. Therefore, the total execution time is O(N)+O(N)=O(N) -
Space complexity : O(1). We only used
A B
2 pointers.
5. Intersecting linked list
Subject :
Give you two linked lists, judge whether they intersect, if intersect, return the intersection node!
Solution 1: Violent solution
Each node of the above linked list is compared with the entire linked list below. In the worst case, if the two linked lists do not intersect, the time complexity is O(n^2), so I won’t demonstrate it here. Let’s explain the time complexity A solution with degree O(n)
Solution 2: Double pointer traversal
Ideas:
We can define two pointers, start traversing from the head of the two linked lists, and then find the difference between the linked lists. After the long linked list has completed the difference, the two linked lists will traverse backwards together, exit when they are the same, and return the same result point.
Specific steps:
1. Define two pointers, traverse backwards from the head of the two linked lists respectively
2. Record the length of the two linked lists
3. Find the difference between the lengths of the linked lists
4. The long linked list finishes the difference
first Then traverse backwards at the same time until the exit is the same
As shown in the picture:
The first step: traverse the intersecting linked list
Step 2: The long chain list first walks through the difference, and then walks together
The code is as follows :
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 一个链表为空永远不可能香蕉
if (headA==null&&headB==null) {
return null;
}
//分别记录headA headB
ListNode A= headA;
ListNode B=headB;
//用来记录链表长度
int count=0;
//用来记录最短长度
int sum=0;
//用来判断哪个链表长
boolean p=false;
//两个链表一起走,有一个为空时,最短长度记录完成
while (A!=null&&B!=null) {
A=A.next;
B=B.next;
count++;
sum++;
}
//继续走长的链表,直到长链表也走完,记录长链表的长度
while (A!=null) {
A=A.next;
count++;
//如果是A链表不为空,那么p为true
p=true;
}
//同上
while (B!=null) {
B=B.next;
//如果是B链表不为空则p不变
count++;
}
//重新找到头
A=headA;
//同上
B=headB;
//让长的先走
int n=count-sum;
//P为真A先走n步
if (p) {
while (n>0) {
A=A.next;
n--;
}//否则B先走
} else {
while (n>0) {
B=B.next;
n--;
}
}//走完链表的差值后,两个链表一起遍历
//香蕉退出循环
while (A!=B) {
A=A.next;
B=B.next;
}
return A;
}
}
Complexity analysis:
-
Time complexity : O(N), a total of traversal of the completed long linked list plus a traversal of the linked list when looking for intersection points, a total of 2*n times (n represents the length of the longest linked list)
-
Space complexity : O(1),