反转链表类型题
leetcode 206
思路
-
迭代:遍历链表,将当前节点的next指向前一个节点,中间过程需要保存前一个节点和下一个节点(反转后最后一个节点指向空)
时间复杂度O(n),空间复杂度O(1)
-
递归:将反转整个链表分解为两个子问题(反转head和反转head以外的其它节点),往下分解为只剩下一个节点(不需要反转),然后反转两个节点一直往上归并直至反转完整个链表
时间复杂度O(n),空间复杂度O(n)(递归调用的栈空间)
代码
迭代
class Solution {
public:
ListNode *reverseList(ListNode *head) {
ListNode *pre = nullptr;
ListNode *cur = head;
ListNode *next;
while (cur) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
递归
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//递归终止条件:当前节点为空或者只有一个节点
if(head == nullptr || head->next == nullptr){
return head;
}
//递的过程
ListNode *newHead = reverseList(head->next);
//归的过程
head->next->next = head;
head->next = nullptr; //最后的节点指向空
return newHead;
}
};
leetcode 92
思路
-
方法一:将需要反转的链表区间反转后与不需要反转的区间拼接起来
时间复杂度O(n),空间复杂度O(1)
-
方法二:头插法,遍历反转区间,将当前节点放到反转起始的位置,直至反转区间节点反转完
时间复杂度O(n),空间复杂度O(1)
代码
方法一
class Solution {
private:
ListNode *reverseList(ListNode *head){
if(!head || !head->next){
return head;
}
ListNode *newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
public:
ListNode *reverseBetween(ListNode *head, int left, int right) {
ListNode *dummyNode = new ListNode(-1);
dummyNode->next = head;
ListNode *pre = dummyNode; //走left-1步找到left前一个节点
for (int i = 0; i < left - 1; i++) {
pre = pre->next;
}
ListNode *rightNode = pre; //再走right - left + 1找到right
for(int i = 0;i < right - left + 1;i++){
rightNode = rightNode->next;
}
ListNode *leftNode = pre->next; //记录left前一个
ListNode *subNode = rightNode->next; //记录right下一个
rightNode->next = nullptr;//截断中间区域
ListNode *midNode = reverseList(leftNode); //反转中间区域
//重新连接
pre->next = midNode;
leftNode->next = subNode;
return dummyNode->next;
}
};
方法二
class Solution {
public:
ListNode *reverseBetween(ListNode *head, int left, int right) {
//头插法
ListNode *dummyNode = new ListNode(-1);
dummyNode->next = head;
ListNode *pre = dummyNode;
for (int i = 0; i < left - 1; i++) {
pre = pre->next;
}
ListNode *cur = pre->next;
ListNode *next;
for (int i = 0; i < right - left; i++) {
next = cur->next;
cur->next = next->next;
next->next = pre->next;
pre->next = next;
}
return dummyNode->next;
}
};
改编题目
题目描述
给定单链表的头指针head,两个整数left和right其中left < right,请你反转从1到left,以及位置right到末尾节点,返回反转后的链表
注:链表长度>=2且left和right范围不超过链表本身
示例
输入
[3,4,5,6,7,8],3,5
输出
[5,4,3,6,8,7]
思路
直接在leetcode92的基础上反转两次[1,left] [right,tail]
代码
class Solution {
private:
ListNode *reverseBetween(LisNode *head, int left, int right) {
//头插法
ListNode *dummyNode = new ListNode(-1);
dummyNode->next = head;
for (int i = 0; i < left - 1; i++) {
pre = pre->next;
}
ListNode *cur = pre->next;
ListNode *next;
for (int i = 0; i < right - left; i++) {
next = cur->next;
cur->next = next->next;
next->next = pre->next;
pre->next = next;
}
return dummyNode->next;
}
public:
ListNode *reverseList(listNode *head, int left, int right) {
ListNode *temp = head;
int tail = 0;
while (temp) {
temp = temp->next;
tail++;
}
//先反转左半边
head = reverseBetween(head, 1, left);
//再翻转右半边
head = reverseBetween(head, right, tail);
return head;
}
};