算法训练营day03 | {203. 移除链表元素, 707.设计链表, 206.反转链表}

第二章链表-part01,知识点为虚拟头结点、双指针原地反转链表、递归写法。

203. 移除链表元素

1.1 看到题目的想法

加上虚拟的头结点,统一任意位置结点的删除操作,比较简单,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode preHead = new ListNode();
preHead.next = head;
ListNode p = preHead.next;
ListNode pre = preHead;
while (p != null) {
if (val == p.val) {
// 删除结点
pre.next = p.next;
} else {
pre = p;
}
p = p.next;
}

return preHead.next;
}
}

1.2 看完代码随想录的想法

  • 设置虚拟头结点的写法,变量定义取名curdummy感觉挺好的。

707. 设计链表

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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package cn.leetcode.list;

/**
* 设计单链表
*/
public class MyLinkedList {

private class ListNode {
int val;
ListNode next;

ListNode(int val) {
this.val = val;
}
}

private ListNode listHead; // 链表虚拟头结点
private int size;

public MyLinkedList() {
listHead = new ListNode(0);
size = 0;
}

/**
* 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
* @param index 链表下标
* @return
*/
public int get(int index) {
ListNode p = listHead.next;
if(index < 0 || index >= size) return -1;
for (int i = 0; i <= index - 1; i++) {
p = p.next;
}
return p.val;
}

/**
* 头插法
* @param val
*/
public void addAtHead(int val) {
ListNode newNode = new ListNode(val);
newNode.next = listHead.next;
listHead.next = newNode;
size++; // 更新size
}

/**
* 尾插法
* @param val
*/
public void addAtTail(int val) {
ListNode newNode = new ListNode(val);
ListNode p = listHead; // 注意null pointer
while(p.next != null) {
p = p.next;
}
p.next = newNode;
newNode.next = null;
size++;
}

/**
* 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如
* 果 index 等于链表的长度,那么该节点会被追加到链表的末尾。
* 如果 index 比长度更大,该节点将 不会插入 到链表中。
* @param index
* @param val
*/
public void addAtIndex(int index, int val) {
if(index == size) {
addAtTail(val);
} else if (index > size) {
return;
} else {
ListNode newNode = new ListNode(val);
ListNode p = listHead.next;
ListNode pre = listHead;
for (int i = 0; i <= index - 1 ; i++) {
pre = p;
p = p.next;
}
// 执行插入操作
newNode.next = pre.next;
pre.next = newNode;
size++;
}
}

/**
* 如果下标有效,则删除链表中下标为 index 的节点。
* @param index
*/
public void deleteAtIndex(int index) {
if(index < 0 || index >= size) return;
ListNode p = listHead.next;
ListNode pre = listHead;
for (int i = 0; i <= index - 1 ; i++) {
pre = p;
p = p.next;
}
// 执行删除操作
pre.next = p.next;
size--;
}
}

206. 反转链表

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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    package cn.leetcode.list;

    public class ReverseList {
    /**
    * 双指针写法,原地反转
    * @param head
    * @return
    */
    public ListNode reverseList(ListNode head) {
    ListNode cur = head;
    ListNode pre = null;
    while(cur != null) {
    ListNode temp = cur.next;
    cur.next = pre;
    pre = cur;
    cur = temp;
    }
    return pre;
    }

    /**
    * 递归写法主函数
    * @param head
    * @return
    */
    public ListNode reverseListV2(ListNode head) {
    return reverse(head, null);
    }

    public ListNode reverse(ListNode cur, ListNode pre) {
    if(cur == null) return pre;
    ListNode temp = cur.next;
    cur.next = pre;
    return reverse(temp, cur);
    }

    }

算法训练营day03 | {203. 移除链表元素, 707.设计链表, 206.反转链表}
http://paopaotangzu.xyz/cn/day03_leetcode/
作者
PROTON TANG
发布于
2025年12月18日
许可协议