算法通关村第二关——链表白银挑战笔记
前言
全文代码均以Java语言复现,主要为自己学习做记录,如有问题,还请各位大佬们指点指点。
这篇讲解单链表链表反转的衍生问题——指定区间反转。
分析
- 因为是指定区间反转,说运用的方法跟整个链表反转是一样的,如:借助虚拟头节点进行反转;不使用虚拟头节点实现链表反转;最后一个就是递归。详情请点击原文。
- 难点就在于是边界的把握(left 和 right)。
- 还有就是对链表反转的理解
头插法
运用虚拟头节点,实现链表反转。是最容易书写出来的方法
class Solution{
public Node reverseBetween(ListNode head,int left,int right){
// 使用虚拟头节点 运用头插法 进而实现链表反转
ListNode dummyNode = new ListNode(-1);
ListNode pre=dummyNode;
ListNode cur= head;
for(int i = 0 ;i<left;i++){
pre=pre.next;
}
cur=pre.next;
for(i=0;i<right-left;i++){
ListNode next=cur.next;
// 这一步很关键 不要让内部单链表断裂
cur.next=next.next;
// 经典头插法 先右连接 后左连接
next.next=pre.next;
pre.next=next;// 前驱节点pre是不会移动的
}
return dummyNode.next;
}
}
穿针引线法(很妙)
class Solution{
public ListNode reverseBetween(ListNode head,int left,int right){
// 虚拟头节点 防止复杂的情况出现 少点判断
ListNode dummyNode = new ListNode(-1);
dummyNode.next=head;
ListNode pre=dummyNode;
// 确定左边界
for(int i= 0;i<left-1;i++){
pre=pre.next;
}
ListNode rightNode= pre;
// 确定右边界
for(int i=0;i<right-left+1;i++){
rightNode=rightNode.next;
}
// 切断一个从left到right的子链
ListNode leftNode=pre.next;
ListNode succ=rightNode.next;
rightNode.next=null;
// 反转切下来的子链
reverseLinkedList(leftNode);
// 穿针引线的核心代码
pre.next=rightNode;
leftNode.next=succ;
return dummyNode.next;
}
// 链表反转——不使用虚拟头节点的方法
private void reverseLinkedList(ListNode head){
ListNode pre=null;
ListNode cur=head;
while(cur!=null){
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
}
}
总结
还是要多反复理解反转链表的流程,通过画图,也可以在编译器中debug,都是对反转流程的理解很好的办法。如有对翻转链表不懂的友友,可以点击此文章.