141. 环形链表
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow=head,fast=head;
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(slow==fast) return true;
}
return false;
}
}
142. 环形链表 II
快指针与满指针相遇时,快指针所走的距离:a+n(b+c)+b即a+(n+1)b+nc
又快指针走过的距离是慢指针的2倍,因此a+(n+1)b+nc=2(a+b)即a=c+(n-1)(b+c)
我们就知道了从相遇点到入环点的距离加上 n−1 圈的环长,恰好等于从链表头部到入环点的距离。
代码
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast=head,slow=head;
//找到相遇处
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(slow==fast) break;
}
if(fast==null || fast.next==null) return null;
fast=head;
while(fast!=slow){
fast=fast.next;
slow=slow.next;
}
return fast;
}
}
求环的长度
- 思路很简单,相遇时把节点记录下来,然后让他走一圈,记录步数就是环的长度了
求链表总长度
- 上一问拿到了环的长度+起点到环的入口的长度即可
- 起点到环的入口的长度?
- 上一问拿到了入口,从起点再走一趟就好了
234. 回文链表
- 快指针走到末端时,慢指针更好在中间(快指针一次两步,慢指针一次走一步)
- 慢指针一边走一边翻转
- 当快指针到终点的时候就可以开始比较了
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode pre=null;
ListNode slow=head;
ListNode fast=head;
//翻转时中用的中间节点
ListNode temp;
while(fast!=null && fast.next!=null){
//翻转
temp=slow.next;
if(pre!=null) slow.next=pre;
pre=slow;
slow=temp;
//走两步
fast=fast.next.next;
}
//节点数为奇数,从下一个开始比较
if(fast!=null) slow=slow.next;
while(slow!=null) {
if(slow.val!=pre.val) return false;
slow=slow.next;
pre=pre.next;
}
return true;
}
}
2095. 删除链表的中间节点
- 虚拟一个头结点,用来避免奇偶带来的影响,当快指针走到尾时,慢指针一定走到所谓中间节点的前一个节点
class Solution {
public ListNode deleteMiddle(ListNode head) {
ListNode dummy=new ListNode(-1);
dummy.next=head;
ListNode slow=dummy,fast=dummy;
while(fast.next!=null&&fast.next.next!=null){
slow=slow.next;
fast=fast.next.next;
}
slow.next=slow.next.next;
return dummy.next;
}
}
206. 反转链表
- 递归法
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null) return head;
ListNode ret=reverseList(head.next);
head.next.next=head;
head.next=null;
return ret;
}
}
- 迭代法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null; //前指针节点
ListNode curr = head; //当前指针节点
//每次循环,都将当前节点指向它前面的节点,然后当前节点和前节点后移
while (curr != null) {
ListNode nextTemp = curr.next; //临时节点,暂存当前节点的下一节点,用于后移
curr.next = prev; //将当前节点指向它前面的节点
prev = curr; //前指针后移
curr = nextTemp; //当前指针后移
}
return prev;
}
}
143. 重排链表
class Solution {
public void reorderList(ListNode head) {
ListNode dummy=new ListNode(-1);
dummy.next=head;
ListNode slow=head;
ListNode fast=head;
while(fast.next!=null&&fast.next.next!=null){
slow=slow.next;
fast=fast.next.next;
}
ListNode slowNext=slow.next;
slow.next=null;
ListNode node2=reverseList(slowNext);
ListNode node1=dummy.next;
while(node2!=null){
ListNode temp1=node1.next;
node1.next=node2;
node2=node2.next;
node1=node1.next;
node1.next=temp1;
node1=node1.next;
}
}
ListNode reverseList(ListNode node){
if(node==null||node.next==null) return node;
ListNode ret=reverseList(node.next);
node.next.next=node;
node.next=null;
return ret;
}
}