题目描述
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
题目分析
全链表反转是会用到三个指针的,而中间链表反转还需要一个表示其实节点,通俗的讲就是一头一尾一中间,标记了各个点,那他们的连接就只要用next来表示了。就以示例中的链表为例,假设我现在有个pre指针在2处,一个cur的指针在3处,一个next指针在4处,那么怎么反转他们呢,先解决中间的连接。next.next=cur cur.next=pre。这样中间的就反转好了,那么再处理两个头,把1记为head,那么就是head.next=next pre.next=next.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) {
ListNode myHead = new ListNode(0);
myHead.next = head;
ListNode newHead = null;
// 保留前一个结点
ListNode curr = myHead;
// 反转开始的结点,随着反转变化
ListNode next = head;
// 反转后的头
ListNode begin = head;
// 反转开始的结点, 不变
ListNode pre = head;
for(int i=1; i<m; i++){
curr = curr.next;
next = next.next;
begin = begin.next;
pre = pre.next;
}
//先反转中间的链表
for(int i =0; i<n - m + 1;i++){
next = next.next;
begin.next = newHead;
newHead = begin;
begin = next;
}
//最后把头反转一下
pre.next = next;
curr.next = newHead;
return myHead.next;
}
}
改进
这个指针太多了,容易晕怎么办,能不能有其他的方式,减少点指针呢,那么下面就要用到链表里的头插法了,不然指针一弄错就会形成死链。
改进代码
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
ListNode cur = dummy.next;
for (int i = 1; i < m; i++) {
pre = pre.next;
cur = cur.next;
}
for (int i = 0; i < n - m; i++) {
ListNode temp = cur.next;
cur.next = temp.next;
temp.next = pre.next;
pre.next = temp;
}
return dummy.next;
}
}
分析
第一个时间复杂度为O(n)
第二个就是O(n)
空间复杂度都为O(1)
[1]https://leetcode-cn.com/problems/reverse-linked-list-ii/submissions/