题意:把链表中m到n的部分反转(1<=m<=n<=length)。
注意要求:在原地反转,也就是不能申请额外的空间,且只能遍历一遍。
例子:
链表 1->2->3->4->5->NULL, m = 2 and n = 4,
返回 1->4->3->2->5->NULL.
解析:
参考最高票的discuss,我们模拟一下逆置的过程:
1-2-3-4-5
先把3放2前面变成
1-3-2-4-5
再把4放3-2前面变成
1-4-3-2-5
循环该怎么做?
首先定义四个指针dummy,pre,start,then。
dummy为head的前置节点,只要题目可能涉及到头节点的变动,都需要声明dummy哑变量,最后返回dummy.next。
pre为一个不变的节点,用来标识在上述逆置过程中m的前置节点,在本题中为1。
start和then为用来逆置的节点,具体作用下面过程会有分析。
第一步,找到m的前置节点pre,然后start是pre的后继,then又是start的后继。在本题中pre为1节点,start为2节点,then为3节点。
第二部,利用pre,start,then这三个指针,从m+1到n的节点,依次放置到pre的后面。pre是永远不动的,因为插入的节点都需要插入它的后面,而start和then每次需要向后移动。即:
start.next = then.next;
then.next = pre.next;
pre.next = then;
then = start.next;
那么本题的代码也就很容易写出来了:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
if(head == null) return null;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
ListNode start = head;
ListNode then = head.next;
for(int i = 0; i < m - 1; i++){
pre = pre.next;
start = start.next;
then = then.next;
}
for(int i = 0; i < n - m; i++){
start.next = then.next;
then.next = pre.next;
pre.next = then;
then = start.next;
}
return dummy.next;
}
}