您的位置:首页 > 其它

[leetcode] Reverse Linked List II 链表反转

2016-07-16 21:31 477 查看
Leetcode上关于链表反转有2题,分别是https://leetcode.com/problems/reverse-linked-list/ https://leetcode.com/problems/reverse-linked-list-ii/
第一题是反转整个链表,第二题是反转链表中位于[m,n]之间的部分。

首先简单说下原地反转整个链表的两种方法:

法一:【递归法】假设从i+1开始到结束的链表L(i+1)已反转,则我们只需将第i个元素置于L(i+1)尾部,即可完成从i开始到结束的链表L(i)的反转,递归完成从第1个元素到结尾的链表L(1)的反转即可。代码如下:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
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;
}
};

法二:【迭代法】从前往后扫描链表,用pre指针指向当前元素的前一个元素,每次将当前元素的next指针指向pre,扫描至最后即可完成整个链表的反转。时间复杂度为O(n),空间复杂度为O(1)。代码如下:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == NULL || head->next == NULL){
return head;
}
ListNode* p = head->next;
ListNode* pre = head;
head->next = NULL;
while(p){
ListNode* tmp = p->next;
p->next = pre;
pre = p;
p = tmp;
}
return pre;
}
};
反转链表的一部分,如[m,n]之间的部分
其实知道了如何反转整个链表,我们完全可以按照上述法二的思路反转链表[m,n]之间的部分,这里需要指针特别记录一下m-1和n+1的位置,便于将反转后部分正确插入。时间复杂度为O(n),空间复杂度为O(1),代码如下:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
if(head == NULL || head->next == NULL || m == n) return head;
ListNode* p = head->next;
ListNode* pre = head, *p1 = head;
int pos = 1;
ListNode* nh = new ListNode(0);
while(p){
++ pos;
if(pos <= m || pos > n){
if(pos == m){
nh = pre;
p1 = p;
}
pre = pre->next;
p = p->next;

}else{
ListNode* tmp = p->next;
p->next = pre;
pre = p;
p = tmp;
if(pos == n){
nh->next = pre;
p1->next = p;
}
}
}
if(m == 1){
return nh->next;
}
return head;
}
};

看了discussion之后发现了另外一种方法,即插入法,特别巧妙。例如,我们要反转1->2->3->4->5的位于[2,4]之间的元素,我们可以依次将3和4向前插入,插入3之后变为1->3->2->4->5,再插入4变为1->4->3->2->5。代码如下:
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
if(head == NULL || head->next == NULL || m == n) return head;
ListNode* p = head;
int pos = 1;
ListNode* nh = new ListNode(0);
nh->next = head;
ListNode* pre = nh;
while(p && pos < m){
++ pos;
pre = p;
p = p->next;
}
// 插入法
for(int i=0; i<n-m; ++i){
ListNode* tmp = p->next;
p->next = tmp->next;
tmp->next = pre->next;
pre->next = tmp;
}
return nh->next;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode 链表