前言
翻转链表有两个角度,三种方式。第一角度,从原链表上将链翻转,或叫指向前一个记录的节点,可递归,可循环。第二角度,完成不用在原链表上费力,采用dummyHead统一空链表/第一节点操作,将需要的节点以头插法(翻转)/尾插法(找符合要求的节点)将节点链接到其后。
一、翻转链表中间部分
二、dummyHead&头插法&尾插法
1、一次扫描 + 翻转链表(另一次扫描)
// 反转链表II
public class ReverseBetween {
/*
target:将链表指定部分翻转。
直接把中间部分分割出来,再翻转,再连接。
*/
public ListNode reverseBetween(ListNode head, int left, int right) {
// 统一空链表/第一个节点的操作。
ListNode dummyHead = new ListNode(0, head);
// 计数
int cnt = 1;
// 生成中间链
ListNode p = dummyHead;
ListNode begin = null, end = null, newHead = null, newTail = null;
while (p.next != null) {
if (cnt == left) {
begin = p;
newHead = p.next;
}
if (cnt == right) {
end = p.next.next;
newTail = p.next;
p.next.next = null;
break;
}
++cnt;
p = p.next;
}
// 翻转链表
reverseList(newHead);
// 拼接链表
begin.next = newTail;
newHead.next = end;
// 返回链表
return dummyHead.next;
}
// 除了for,还可递归/头插入,共3种角度解法。一类在链表上面该,类是将节点重现组合成新链。
private void reverseList(ListNode head) {
ListNode pre = null;
while (head != null) {
ListNode next = head.next;
head.next = pre;
pre = head;
head = next;
}
}
// 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;
}
}
}
2、一次扫描&头插法&尾插法(进阶)
// 进阶:一次扫描。
class ReverseBetween2 {
/*
target:将链表指定部分翻转。
一次扫描,将符合的地方翻转即可。
*/
public ListNode reverseBetween(ListNode head, int left, int right) {
// 统一空链表/第一个节点的操作。
ListNode dummyHead = new ListNode();
ListNode newHead = dummyHead,tail = dummyHead;
// 把不需要翻转/需要翻转的节点以尾插法/头插法
// 计数
int cnt = 1;
while (head != null) {
// 取节点
ListNode node = head;
// 更新下一个head
head = head.next;
// 头插法
if (left <= cnt && cnt <= right) {
node.next = newHead.next;
newHead.next = node;
// 判定是否需要更新尾巴节点。
if (tail == dummyHead) tail = tail.next;
}
// 尾插法
else {
// 尾插法,需要更新头
newHead = node;
// 插入节点
node.next = null;
tail.next = node;
tail = tail.next;
}
// 更新走到那里了。
++cnt;
}
// 返回链表
return dummyHead.next;
}
// 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;
}
}
}
总结
1)dummy节点的使用,让操作链表方便起来,配合上头插法/尾插入,可玩转链表操作。
参考文献
[1] LeetCode 翻转链表II