目录
L206 反转链表
题目描述
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例1:
示例2:
题解
方法一:迭代
假设链表为 1→2→3→∅,我们想要把它改成 ∅←1←2←3。
我们考虑遍历链表,将每个节点的next指针改为指向前一个节点。但是链表是单向的,当遍历到某个节点时,我们已经没有前一个节点的引用了,所以需要使用一个prev引用来保存当前节点的前一个节点。
然后做以下迭代步骤:
- 保存curr的next引用
- 设置当前节点的next指向prev
- 将prev指向当前节点
- 将curr指向next
class Solution {
public ListNode reverseList(ListNode head) {
ListNode curr = head;
ListNode prev = null;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
复杂度分析
时间复杂度:O(N),遍历一次。
空间复杂度:O(1)
方法二:递归
假设链表为:
n1→…→n**k−1→n**k→n**k+1→…→n**m→∅
若从节点 n**k+1 到 n**m 已经被反转,而我们正处于 n**k
n1→…→n**k−1→n**k→n**k+1←…←n**m
我们希望 n**k+1 的下一个节点指向 n**k。
所以,n**k.next.next=n**k。
需要注意的是:
- next指针的修改
- 反转后的链表的链尾节点的next应该为null
- 在递归过程中应该要将反转后的链表头节点返回
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
}
复杂度分析
时间复杂度:O(N)
空间复杂度:O(N),因为递归占用栈空间
L92 反转链表 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]
题解
方法一:一遍扫描
将链表分成三段,反转中间的部分,然后将左中右重新相接。
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummy = new ListNode(0, head);
// 0.整个链表分为左中右三段
// 1.首先找到左链表的尾部
ListNode node = dummy;
for (int i = 1; i < left; i++) {
node = node.next;
}
ListNode leftListTail = node;
// 2.反转中间链表
node = node.next;
ListNode midListHead = node;
ListNode prev = null;
for (int i = left; i <= right; i++) {
ListNode next = node.next;
node.next = prev;
prev = node;
node = next;
}
// 3.重新相接
leftListTail.next = prev;
midListHead.next = node;
return dummy.next;
}
方法二:穿针引线
pre永远指向左链表的最后一个节点。
curr永远指向右链表的第一个节点。
每次迭代:
- 先将
curr
的下一个节点记录为next
- 执行操作 ①:把
curr
的下一个节点指向next
的下一个节点 - 执行操作 ②:把
next
的下一个节点指向pre
的下一个节点 - 执行操作 ③:把
pre
的下一个节点指向next
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
// 设置 dummyNode 是这一类问题的一般做法
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode pre = dummyNode;
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
ListNode cur = pre.next;
ListNode next;
for (int i = 0; i < right - left; i++) {
next = cur.next;
cur.next = next.next;
next.next = pre.next;
pre.next = next;
}
return dummyNode.next;
}
}
L25 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]
题解
方法一:模拟
思路就是先向后遍历k个节点,如果剩余元素个数少于k个,则直接返回;如果大于等于k个,就进行翻转。
反转完成之后,需要重新将它接回原链表。
class Solution {
public ListNode reverseKGroup(ListNode list, int k) {
ListNode dummy = new ListNode(0, list);
ListNode tail = dummy;
while (true) {
ListNode curr = tail;
for (int i = 0; i < k; i++) {
curr = curr.next;
if (curr == null) {
return dummy.next;
}
}
ListNode nextKGroupHead = curr.next;
ListNode currKGroupHead = tail.next;
ListNode prev = nextKGroupHead;
curr = tail.next;
while (curr != nextKGroupHead) {
ListNode nxt = curr.next;
curr.next = prev;
prev = curr;
curr = nxt;
}
tail.next = prev;
tail = currKGroupHead;
}
}
}
标签:head,curr,反转,next,链表,ListNode,节点
From: https://www.cnblogs.com/zhaoqi94/p/18290871