逆转部分LinkList,和逆转整个LinkList的题目是一样的,沿用之前的思路就可以,新建一个dummyNode,把要逆转的部分通过头插法连接起来。
这道题稍微有点麻烦,就是分步骤:
1,找到逆转部分的之前一个node,作为第一个attach point
2,确定逆转部分的最后一个node,作为第二个attach point
3,完成扭转之后,attach两次既可!
一个技巧,因为m可以等于1,那么逆转部分的前一个node怎么确定呢?那就通过新建一个dummyHead,连在head之前,这样就非常方便了,很多情况下,通过dummyHead可以是问题简化很多。代码如下
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
if(head==null || head.next==null) return head;
ListNode dummyHead= new ListNode(0);
dummyHead.next=head;
ListNode curr=dummyHead;
int jump=0;
while(jump<m-1){
curr=curr.next;
jump++;
} // after while loop, jump=m-2 and curr points to the node before m-th node
ListNode frontAttach=curr; // set the anchor
// advance 1 node
curr=curr.next;
jump++;
// use the same idea of reverse the whole list
ListNode dummy= new ListNode(0);
ListNode backAttach=curr;
while(jump<=n){
ListNode target=curr;
curr=curr.next;
target.next=dummy.next;
dummy.next=target;
jump++;
}
// do 2 attach, for the reversed segment
frontAttach.next=dummy.next;
backAttach.next=curr;
return dummyHead.next; // Do NOT return head, it is wrong, when m==1
}
}
参考了别人的解法,有一个while循环就完成逆转的,代码是比较简洁,但是while内部的多次node 移动不是非常intuitive,需要画图才看得清楚,可能在熟悉之后还是可以使用的,如果头脑里没有这个画面,还是不要轻易使用, 容易出错。代码如下
public ListNode reverseBetween(ListNode head, int m, int n) {
if(head == null) return null;
ListNode dummy = new ListNode(0); // create a dummy node to mark the head of this list
dummy.next = head;
ListNode pre = dummy; // make a pointer pre as a marker for the node before reversing
for(int i = 0; i<m-1; i++) pre = pre.next;
ListNode start = pre.next; // a pointer to the beginning of a sub-list that will be reversed
ListNode then = start.next; // a pointer to a node that will be reversed
for(int i=0; i<n-m; i++)
{
start.next = then.next;
then.next = pre.next;
pre.next = then; // 以上三句就是每次把then node移动到pre后面,这样就完成了逆转,pre和start之间的node顺序已经稳定,所以不需要做改变
then = start.next; // 始终保持then在start后面
}
return dummy.next;
}
结合我代码的思路,这上面的代码其实还比较好理解,
第一个for loop,通过移动m-1次,把光标指针移到m-1个node处,然后初始化start,和始终在start后面的end
第二个for loop,本质就是挪动n-m次node,所以有i=0; i<n-m,每次挪动需要换图来理解,至少画2个循环才看得清楚,第一次的pre.next 和第二次的pre.next的区别就让你看得清楚了。有了理解和画面感,还是比较容易记忆的。