反转链表解析
学习过链表的朋友们都知道,链表的节点是由指针和数值组成的,每个指针都指向下一个链表,这就是链表的逻辑结构,而反转链表实际上就是将指针反转过来,指向前一个元素,且头节点指向null
在解决此类问题的时候,我们可以使用cur
来代表当前元素, pre
来代表当前元素的前一个元素,nxt
来代表当前元素的后一个元素。
而过程则是从头节点开始,头节点指向null
,头节点的下一个节点指向头节点……,如此往复,就是下面的过程:
反转完成之后,pre
指向这一段链表的末尾,cur
指向这一段的下一个节点。
理清楚之后,我们就可以看下面的题啦~
206. 反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
题目分析
这是一道简单题,实际上就是简单地描述一个反转链表的过程,代码如下:
代码
/**
* 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 cur = head;
while(cur != null){
ListNode nxt = cur.next;
cur.next = pre;
// 下面这俩顺序不能反!
pre = cur;
cur = nxt;
}
return pre;
}
}
92.反转链表II
给你单链表的头指针 head
和两个整数 left
和 right
,其中 left <= right
。请你反转从位置 left
到位置 right
的链表节点,返回 反转后的链表 。
示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]
提示:
- 链表中节点数目为
n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n
题目分析
本题其实和上题类似,多了一个范围设定
[
l
e
f
t
,
r
i
g
h
t
]
[left, right]
[left,right],我们假设这一段链表的前面一个链表为p0
,由于我们在分析反转链表时得到了一个结论:**反转完成之后,pre
指向这一段链表的末尾,cur
指向这一段的下一个节点。**那么我们此时就可以假设pre
是
r
i
g
h
t
right
right对应的节点,cur
是
r
i
g
h
t
right
right后的一个节点。
如下图,反转完成之后,p0.next
指向cur
,而p0
指向pre
;
此题分析到这还没完哦,当left = 1
时,没有p0
节点了怎么办?很简单,我们只需要在一整段链表前加一个”哨兵节点“就可以啦~
代码
/**
* 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 reverseBetween(ListNode head, int left, int right) {
ListNode dummy = new ListNode(0, head);
ListNode p0 = dummy;
// 使p0到达反转这一段的上一个节点
for(int i = 0; i < left - 1; i ++) p0 = p0.next;
ListNode pre = null;
ListNode cur = p0.next;
for(int i = 0; i < right - left + 1; i ++){
ListNode nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
p0.next.next = cur;
p0.next = pre;
return dummy.next;
}
}
25. K个一组翻转链表
给你链表的头节点 head
,每 k
个节点一组进行翻转,请你返回修改后的链表。
k
是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k
的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
提示:
- 链表中的节点数目为
n
1 <= k <= n <= 5000
0 <= Node.val <= 1000
题目分析
这道题和上道题其实就是一样的,只是多了一个 k k k来控制翻转,具体我们看图:
代码
/**
* 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 reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(0, head);
ListNode p0 = dummy;
// 获取链表长度
ListNode cur = head;
int n = 0;
while(cur != null){
n ++;
cur = cur.next;
}
cur = head;
ListNode pre = null;
while(n >= k){
n -= k;
for(int i = 0; i < k; i ++){
ListNode nxt = cur.next;
cur.next = pre;
pre = cur;
cur = nxt;
}
ListNode nxt = p0.next;
p0.next.next = cur;
p0.next = pre;
p0 = nxt;
}
return dummy.next;
}
}