链表 --面试经典150题

tobegold574 Lv5

反转链表 II

做题过程

比反转链表I多了要处理环的问题,但是其实也不需要显式处理,可以用好的代码代替显式处理,这个地方弄得焦头烂额也没弄对。

算法概述

原题

本题要求为反转给出范围内的链表。

  • 时间复杂度为O(n)
  • 空间复杂度为O(1)

JAVA

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
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
// 空链表和空区间检查
if (head == null || left == right) {
return head;
}

// 创建一个哑节点,简化边界操作
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prev = dummy;

// 定位到 left - 1 位置(即反转区间左侧外部第一个节点)
for (int i = 0; i < left - 1; i++) {
prev = prev.next;
}

ListNode curr = prev.next;
ListNode next = curr.next;

// 开始反转过程(不断将后面的节点,即next,插入到前面)
for (int i = 0; i < right - left; i++) {
// 把curr和next的后一个节点连接
curr.next = next.next;
// 把next与prev的后一个节点连接(插入)
next.next = prev.next;
// 把prev与next连接(插入)
prev.next = next;
// 只需要更新next
next = curr.next;
}

return dummy.next; // 返回新的链表头
}
}

总结

迭代 不同,上述解法可以 保留前驱 ,并且curr自动移动 的,只需更新next即可,因为在插入的过程中,区间是固定的,所以前驱是固定的,并且每次操作的对象都是curr之后的节点(往前插入),而curr会逐渐从区间内第一个节点变成最后一个节点。

删除排序链表中的重复元素 II(medium)

做题过程

思路没问题,循环写多了,还没写对,幸好没弄成环,不然更搞笑。

算法概述

原题

本题要求如题所示。一般模拟即可。

  • 时间复杂度为O(n)
  • 空间复杂度为O(1)

JAVA

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
class Solution {
public ListNode deleteDuplicates(ListNode head) {

ListNode dummy = new ListNode();
dummy.next = head;
ListNode current = dummy;

while (current.next != null && current.next.next != null) {
// 如果当前节点和下一个节点的值相同
if (current.next.val == current.next.next.val) {
// 记录重复值
int duplicateVal = current.next.val;
// 跳过重复节点
while (current.next != null && current.next.val == duplicateVal) {
current.next = current.next.next;
}
} else {
// 否则正常向后移动
current = current.next;
}
}
// 返回删除重复节点后的链表
return dummy.next;
}
}

总结

current需要从哑结点开始,不然哑结点用来处理初始边界存在重复的意义就不复存在了,而且这样只需要写一个循环(循环内通过记录重复值来辅助删除操作),不用再来一个循环先处理一遍边界情况(我加了dummy还这么写🥲)。控制的是current.next的变化,而不是current变化,重复的直接交给JAVA的垃圾回收机制即可(c++还要delete)。

旋转链表(medium)

做题过程

就想着改下值就行,但其实不行,必须改节点。

算法概述

原题

本题要求为对给出的链表向右旋转(假设循环)给定次数。直接模拟。

  • 时间复杂度为O(n)
  • 空间复杂度为O(1)

JAVA

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
class Solution {
public ListNode rotateRight(ListNode head, int k) {
// 如果链表为空或k为0,直接返回链表
if (head == null || head.next == null || k == 0) {
return head;
}

// 计算链表长度并找到链表尾节点
ListNode t = head;
int length = 1;
while (t.next != null) {
t = t.next;
length++;
}

// 将链表尾节点连接到头节点,形成环状链表
t.next = head;

// 计算实际需要旋转的步数
k = k % length;

// 找到旋转后的新尾节点
int stepsToNewHead = length - k;
ListNode newTail = head;
for (int i = 1; i < stepsToNewHead; i++) {
newTail = newTail.next;
}

// 新的头节点是newTail的下一个节点
ListNode newHead = newTail.next;

// 将新尾节点的next设置为null,断开环状链表
newTail.next = null;

return newHead;
}
}

总结

链表是很 灵活 的,根本不需要动内部的节点,直接动头和尾就行, 节点内部相对关系不需要更改
还要注意的是:

  • k = k % length;:计算实际移动步数
  • t.next = head;:形成环状链表(其实只需要这一步即可,不需要处理索引什么的)
  • ListNode newHead = newTail.next;:形成环之后头尾节点直接相邻,很易于通过其一找到另一个

分隔链表(medium)

做题过程

就是拿个链表存一下大于等于给定值的节点就行了。

算法概述

原题

本题要求为将小于给定值的节点放在大于等于给定值的节点之前(不要改变相对顺序)。就是模拟。

  • 时间复杂度为O(n)
  • 空间复杂度为O(k):多少个比给定值大的节点

JAVA

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
/**
* 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 partition(ListNode head, int x) {
ListNode dummy=new ListNode();
dummy.next=head;
ListNode curr=dummy;
List<ListNode> last=new ArrayList<>();

// 遍历和保存大于等于的节点,并且将它们从原链表中拿出去
while(curr.next!=null){
if(curr.next.val>=x){
last.add(curr.next);
curr.next=curr.next.next;
}else{
curr=curr.next;
}
}
// 再装到原链表尾部
for (int i = 0; i < last.size(); i++) {
curr.next = last.get(i);
curr = curr.next;
}
curr.next=null;
return dummy.next;
}
}

总结

官方题解是 维护两个链表 ,都遍历原链表,但一个链表 只存小于等于给定值的节点 ,另外一个链表存 大于等于给定值的节点 ,遍历完了拼接一下就行了,这样就只是改了一下前驱后驱的相对关系,不用额外的空间复杂度。

  • Title: 链表 --面试经典150题
  • Author: tobegold574
  • Created at : 2024-12-23 11:03:14
  • Updated at : 2024-12-25 10:45:07
  • Link: https://tobegold574.me/2024/12/23/链表-面试经典150题/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments