目录
206. 反转链表Reverse a LinkedList (easy)
92. 反转链表 IIReverse a Sub-list (medium)
25. K 个一组翻转链表Reverse every K-element Sub-list (medium)
在众多问题中,题目可能需要你去翻转链表中某一段的节点。通常,要求都是你得原地翻转,就是重复使用这些已经建好的节点,而不使用额外的空间。这个时候,原地翻转模式就要发挥威力了。
这种模式每次就翻转一个节点。一般需要用到多个变量,一个变量指向头结点(下图中的current),另外一个(previous)则指向咱们刚刚处理完的那个节点。在这种固定步长的方式下,你需要先将当前节点(current)指向前一个节点(previous),再移动到下一个。同时,你需要将previous总是更新到你刚刚新鲜处理完的节点,以保证正确性。
判断该模式
- 如果你被问到需要去翻转链表,要求不能使用额外空间的时候
力扣经典题
206. 反转链表Reverse a LinkedList (easy)
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev=null,curr=head;
while(curr!=null){
ListNode nextTemp=curr.next;
curr.next=prev;
prev=curr;
curr=nextTemp;
}
return prev;
}
}
class Solution {
public ListNode reverseList(ListNode head) {
//递归终止条件(最小子问题)
if(head==null||head.next==null){
return head;
}
ListNode p=reverseList(head.next);
head.next.next=head;
head.next=null;
return p;
}
}
92. 反转链表 IIReverse a Sub-list (medium)
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode dummy=new ListNode(-1);//哨兵节点,结尾返回值是dummy.next
pre.next=head;
ListNode prev=dummy,con=dummy,curr=head;
int k=1;//表示当前操作的是第几个节点
while(k<=n){
if(k<m){
con=curr;//con是指针指向第 m 个结点的前一个结点,它相当于反转链表的头部前一个
prev=curr;
curr=curr.next;
}else if(k>=m){
ListNode nextTemp=curr.next;
curr.next=prev;
prev=curr;
curr=nextTemp;
}
k++;
}
//至此m到n的子链已经反转完毕,再处理反转子链的头节点,尾节点与不动部分的链接
con.next.next=curr;//此时的con.next是tail,是反转链表的尾部
con.next=prev;
return dummy.next;
}
}
25. K 个一组翻转链表Reverse every K-element Sub-list (medium)
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy=new ListNode(-1);//哨兵节点
dummy.next=head;
ListNode curr=head;//用来遍历链表,判断当前末尾是否足够k个节点
ListNode tail=dummy;//标记链表翻转后的尾巴节点
ListNode con=dummy;//标记链表翻转后链接在哪个节点后面
ListNode pre=dummy;//标记链表翻转后的头节点
while(curr!=null){
int i;
tail=curr;
for(i=0;i<k;i++){
pre=curr;
if(curr==null){
break;
}
curr=curr.next;
}
if(i==k){//还有k个节点的情况
reserve(tail,k);//翻转
con.next=pre;
tail.next=curr;
}else{//末尾不含k个节点的情况
con.next=tail;
}
con=tail;
}
return dummy.next;
}
public void reserve(ListNode head,int k){
ListNode prev=head,curr=head;
for(int i=0;i<k;i++){
ListNode nextTemp=curr.next;
curr.next=prev;
prev=curr;
curr=nextTemp;
}
}
}
力扣题
//设置哨兵节点,一个一个的将最后一个节点移到dummy后,很笨的方法,因为最后一个节点不好维护,需要一次一次的遍历寻找最后一个节点
//优化:遍历一遍链表知道长度后,与K比较知道将哪段链表一起移到头部
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head==null){
return head;
}
ListNode dummy=new ListNode(-1);//哨兵节点,链表题常用技巧
dummy.next=head;
ListNode curr=head,tail=curr;
int len=0;
while(curr!=null){
tail=curr;//尾节点
curr=curr.next;
len++;
}
if(k%len==0){
return head;
}
int start=0;//第start个节点的后一个节点移到头部去
if(k>len){
start=len-k%len;
}
if(k<len){
start=len-k;
}
curr=dummy;
for(int i=0;i<start;i++){
curr=curr.next;
}
tail.next=head;
dummy.next=curr.next;
curr.next=null;
return dummy.next;
}
}