1.翻转链表
剑指 Offer II 024. 反转链表
给定单链表的头节点 head
,请反转链表,并返回反转后的链表的头节点。
示例1:
1 2
| 输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
|
示例2:
1 2
| 输入:head = [1,2] 输出:[2,1]
|
示例3:
提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
1.1 递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public ListNode reverseList(ListNode head) { return reverse(head); }
private ListNode reverse(ListNode head) { if(head == null) { return head; } if(head.next == null) { return head; } ListNode last = reverse(head.next); head.next.next = head; head.next = null; return last; } }
|
1.2 双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public ListNode reverseList(ListNode head) { ListNode prev = null; ListNode cur = head; ListNode temp = null; while(cur != null) { temp = cur.next; cur.next = prev; prev = cur; cur = temp; } return prev; } }
|
2. 两两交换
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例1:
1 2
| 输入:head = [1,2,3,4] 输出:[2,1,4,3]
|
示例2:
示例3:
提示:
- 链表中节点的数目在范围
[0, 100]
内
0 <= Node.val <= 100
2.1 递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public ListNode swapPairs(ListNode head) { if(head == null || head.next == null) { return head; } ListNode next = head.next; ListNode newSwapNode = swapPairs(next.next); next.next = head; head.next = newSwapNode; return next; } }
|
2.2 虚拟头结点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public ListNode swapPairs(ListNode head) { ListNode dumpNode = new ListNode(0); dumpNode.next = head; ListNode prev = dumpNode; while(head != null && head.next != null) { ListNode temp = head.next.next; prev.next = head.next; head.next.next = head; head.next = temp; prev = head; head = head.next; } return dumpNode.next; } }
|
3. 删除倒数第n节点
19. 删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例 1:
1 2
| 输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
|
示例 2:
1 2
| 输入:head = [1], n = 1 输出:[]
|
示例 3:
1 2
| 输入:head = [1,2], n = 1 输出:[1]
|
3.1 数学
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { int length = getLenth(head); ListNode dummyNode = new ListNode(0); dummyNode.next = head; int num = length - (n - 1) - 1; ListNode prev = dummyNode; while(num > 0) { prev = prev.next; num -= 1; } prev.next = prev.next.next; return dummyNode.next; } private int getLenth(ListNode head) { ListNode p = head; int length = 0; while(p != null) { length++; p = p.next; } return length; } }
|
3.2 双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummyNode = new ListNode(0); dummyNode.next = head;
ListNode fast = dummyNode; ListNode slow = dummyNode; while(n > 1) { fast = fast.next; n--; } ListNode prev = null; while(fast != null && fast.next != null) { prev = slow; fast = fast.next; slow = slow.next; } prev.next = slow.next; slow.next = null; return dummyNode.next; } }
|
4. 链表相交
面试题 02.07. 链表相交
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例1:
1 2 3 4 5
| 输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 输出:Intersected at '8' 解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。 在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
|
示例2:
1 2 3 4 5
| 输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Intersected at '2' 解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
|
示例3:
1 2 3 4 5
| 输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 输出:null 解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。 由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 这两个链表不相交,因此返回 null 。
|
提示:
listA 中节点数目为 m
listB 中节点数目为 n
0 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
如果 listA 和 listB 没有交点,intersectVal 为 0
如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]
4.1 指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { int lenA = getLength(headA); int lenB = getLength(headB);
int dfLenAB = lenA - lenB; ListNode curA = headA; ListNode curB = headB; if(dfLenAB >= 0) { while(dfLenAB > 0) { curA = curA.next; dfLenAB--; } } else { dfLenAB = -dfLenAB; while(dfLenAB > 0) { curB = curB.next; dfLenAB--; } } while(curA != null) { if(curA == curB) { return curA; } curA = curA.next; curB = curB.next; } return null; } private int getLength(ListNode head) { ListNode p = head; int length = 0; while(p != null) { length++; p = p.next; } return length; } }
|
5. 环形链表
141. 环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例1:
1 2 3
| 输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
|
示例2:
1 2 3
| 输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
|
示例3:
1 2 3
| 输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
|
提示:
- 链表中节点的数目范围是
[0, 104]
-105 <= Node.val <= 105
pos
为 -1
或者链表中的一个 有效索引 。
5.1 快慢指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Solution { public boolean hasCycle(ListNode head) { if(head == null) { return false; } ListNode fast = head.next; ListNode slow = head; while(fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; if(fast == slow) { return true; } } return false; } }
|