0%

链表

总目录

  1. 链表的中间节点
  2. 反转链表
  3. 回文链表
  4. 重排链表
  5. 移除链表元素
  6. 两两交换链表中的节点
  7. 合并两个有序链表

链表的中间节点-快慢指针

题号:876
给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

输入:head = [1,2,3,4,5]

输出:[3,4,5]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode p = head;
ListNode q = head;
while(q != null && q.next != null){
p = p.next;
q = q.next.next;
}
return p;
}
}
  • 当快指针遍历完时,慢指针刚好在整个链表中间。

反转链表

题号:206

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

输入:head = [1,2,3,4,5]

输出:[5,4,3,2,1]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode q = head;
while(q != null){
ListNode nxt = q.next;
q.next = pre;
pre = q;
q = nxt;
}
return pre;
}
}

回文链表

-前置 :链表的中间节点反转链表
题号:234

给你一个单链表的头节点 head,请判断该链表是否为回文链表。

  1. 快慢指针找到链表中点(偶数长度时取后半段起点,即第二个中间节点);
  2. 反转后半段链表
  3. 用两个指针分别从头节点反转后的后半段头节点同步遍历比较;
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
class Solution {
public boolean isPalindrome(ListNode head) {
// 快慢指针
ListNode fast =head;
ListNode slow = head;
while (fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
// 反转
ListNode pre = null;
ListNode cur = slow;
while (cur != null) {
ListNode nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}

while (pre != null){
if(pre.val != head.val){
return false;
}
head = head.next;
pre = pre.next;
}
return true;
}
}

类似例题

题号:9 回文数

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public boolean isPalindrome(int x) {
if(x < 0 || x > 0 && x % 10 == 0){
return false;
}
int rev = 0;
while(rev < x / 10){
rev = rev * 10 + x % 10;
x /= 10;
}
return rev == x || rev == x / 10;
}
}

重排链表

题号:143

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 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
25
26
27
28
29
30
31
32
33
34
class Solution {
public void reorderList(ListNode head) {
ListNode mid = middle(head);
ListNode head2 = reverse(mid);
while(head2.next != null){
ListNode nxt = head.next;
ListNode nxt2 = head2.next;
head.next = head2;
head2.next = nxt;
head = nxt;
head2 = nxt2;
}
}

private ListNode reverse(ListNode head){
ListNode pre = null, cur = head;
while(cur != null){
ListNode nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
return pre;
}

private ListNode middle(ListNode head){
ListNode slow = head, fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}

移除链表元素

题号:203

输入:head = [1,2,6,3,4,5,6], val = 6

输出:[1,2,3,4,5]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode();
dummy.next = head;
ListNode cur = dummy;
while(cur.next != null ){
if(cur.next.val == val){
cur.next = cur.next.next;
}
else{
cur = cur.next;
}
}
return dummy.next;
}
}

两两交换链表中的节点

题号:24

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

输入:head = [1,2,3,4]

输出:[2,1,4,3]

  • 方法一:迭代
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0, head);
ListNode node0 = dummy;
ListNode node1 = head;
while (node1 != null && node1.next != null) {
ListNode node2 = node1.next;
ListNode node3 = node2.next;

node0.next = node2; // 0 -> 2
node2.next = node1; // 2 -> 1
node1.next = node3; // 1 -> 3

node0 = node1;
node1 = node3;
}
return dummy.next;
}
}
  • 方法二:递归
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 node1 = head;
ListNode node2 = head.next;
ListNode node3 = node2.next;

node1.next = swapPairs(node3);
node2.next = node1;

return node2;
}
}

合并两个有序链表

题号:21

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

输入:l1 = [1,2,4], l2 = [1,3,4]

输出:[1,1,2,3,4,4]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode();
ListNode cur = dummy;
while(list1 != null && list2 != null){
if(list1.val < list2.val){
cur.next = list1;
list1 = list1.next;
} else {
cur.next = list2;
list2 = list2.next;
}
cur = cur.next;
}
cur.next = list1 != null ? list1 : list2;
return dummy.next;
}
}