题目
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
来源:力扣(LeetCode)
链接:link
解题思路
首先我们先分析题目,这道题类似于链表的反转,只不过设定了反转的范围,所以解题思路一个是我认为难点在于:
- 链表的反转
- 特殊情况的处理(比如m=1)
- 链表的连接
首先我们先来分析第一个问题,这里涉及到单链表的反转,参考一篇文章:link
自己总结如下:
- 第一种方法:
设置一个头节点 start并初始化为NULL,然后从原链表的头部一个一个取节点并插入到新链表的头部,具体代码如下:
ListNode* change(ListNode* head){
ListNode* start = NULL;
ListNode* p=head; //p指针为工作节点
ListNode* temp;//保存下一个节点
while(p!=NULL)
{
tmp = p -> next;
p -> next = newh;//将节点插入到头节点
newh = p;//然后设置新的头节点为新插入的节点
p = tmp;//重新设置工作节点p
}
return newh;
}
- 第二种方法:
每次都将原第一个结点之后的那个结点放在新的表头后面
ListNode* ReverseList(ListNode* head) {
if(head == NULL)
return head;
ListNode *res,*first,*temp;
res = new ListNode(-1);//设置新的头节点
res->next = head;
first = res->next; //first 始终为第一个结点,不断后移,res为新表头
while(first->next!=NULL)
{
temp = first->next;
first->next = temp->next;
//将头节点放在新表头的后面
temp->next = res->next;
res->next = temp;
}
return res->next;
}
对于第二个难点,特殊情况的处理:
- 当m==n时,证明没有要反转的链表,直接返回
- 当m=1时,会出现的问题是:我们会直接跳过头节点(因为使用了node=node->next),所以我们设置一个哑节点(这个思想是从分割链表中得到的),然后设置哑节点的next指向头节点
对于链表的连接,主要在于:前面的链表和反转链表的连接,反转链表和后面未反转的链表的连接
所以具体整个代码如下:
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
if (m == n) //如果两者相等,直接返回头节点
return head;
if (head == NULL)
return NULL;
int i = 1;
ListNode emp(0); //设置哑节点
emp.next = head;
ListNode* node = &emp;
ListNode* Head=NULL;//反转链表的头节点
ListNode* first,*end;
ListNode* temp=NULL;
while (i < m ) {
node = node->next;
i++;
}
first=end = node->next; //假设不设置哑节点,则会直接跳过头节点
i = 0;
//进行链表的反转,用的是第一种方法
while (i <= n - m) {
temp = first->next;
first->next = Head;
Head = first;
first = temp;
i++;
}
end->next = temp; //这里连接的是反转链表和后面未反转链表的连接
node->next = Head;
return emp.next;
}
};