1、可以判断单向链表中是或否含有环。【快慢指针】
思路:慢指针slow指向头结点,快指针fast指向头结点的next结点,当fast != null && fast.next != null的时候,slow每次移动一步,fast每次移动两步,如果fast == slow,即快慢指针相遇,说明链表中含有环。
public boolean hasCycle(ListNode head) {
//使用快慢指针的思想解决问题(追击问题)
if (head == null) return false;
ListNode slow = head; // 慢指针
ListNode fast = head.next; // 快指针
// 在fast不等于空的前提下,一直进行到 fast 追赶到 slow
while (fast != null && fast.next != null){
if (slow == fast) return true;
slow = slow.next; // 慢指针每次前进一步
fast = fast.next.next; // 快指针每次前进两步
}
return false;
}
该思路也可以找到环的入口:在上述的思路下,让a指针指向head,b指向slow.next,然后同时后移,当a和b相遇的时候,a指向环的入口。
public ListNode cycleEntrance(ListNode head) {
ListNode a = head;
ListNode slow = head;
ListNode fast = head.next;
while (fast != null && fast.next != null){
if (slow == fast) break;
slow = slow.next;
fast = fast.next.next;
}
ListNode b = slow.next;
while (a != b){
a = a.next;
b = b.next;
}
return a;
}
2、可以找到单向链表中的倒数第k个结点。【快慢指针】
思路:链表的长度为 len,需要找到倒数第k【从1开始计数】个节点(即找到正数第len-k【从0开始计数】个节点),让fast和slow都指向头结点,首先先让fast移动k步,然后slow和fast同时每次移动一步,当fast==null的时候,
此时slow正好指向第len-k个节点,即倒数第k个节点。
public int kthToLast2(ListNode head, int k) {
ListNode fast = head;
ListNode slow = head;
while (k > 0){
k--;
fast = fast.next;
}
while (fast != null){
slow = slow.next;
fast = fast.next;
}
return slow.val;
}
3、可以寻找到单向链表的中间结点。【快慢指针】
思路:慢指针slow指向头结点,快指针fast也指向头结点,当fast != null && fast.next != null的时候,slow每次移动一步,fast每次移动两步,最终slow指向中间结点。
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
4、可以让两个长度不同的链表同时到达尾结点。【双指针】
思路:链表headA和headB,la,lb分别指向头结点,然后分别后移,当某一个为null的时候,让其指向另外一个链表的头结点,再一步后移,这样,两个指针就会同时到达另外一个链表的尾结点。(因为两个链表的总长是一定的)
这个思路可以解决两个链表是否相交的问题,即时候含有相同的结点,不仅针对结点的val。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode la = headA;
ListNode lb = headB;
while (la != lb){
la = (la == null) ? headB : la.next;
lb = (lb == null) ? headA : lb.next;
}
return la;
}