给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
思路:
方法一: 递归
对于递归算法,最重要的就是明确递归函数的定义,不要跳进具体的细节中。
比如对于这道题,递归函数reverseList
的定义就是:
输入一个节点head
,将以head
为起点的链表反转,并返回反转后的头节点。
比如我们反转
我们经过
1
| ListNode *dummy = reverseList(head->next);
|
之后,整个链表就变为了:
此时我们只需要让2
指向1
,1
指向nullptr
,然后返回dummy
即:
1 2 3
| head->next->next = head; head->next = nullptr; return dummy;
|
我们就得到了:
最后,递归函数需要有终止条件base case
:
1 2 3
| if(head == nullptr || head->next == nullptr){ return head; }
|
综上,代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public: ListNode* reverseList(ListNode* head) { if(head == nullptr || head->next == nullptr){ return head; } ListNode *dummy = reverseList(head->next); head->next->next = head; head->next = nullptr; return dummy; } };
|
迭代:
我们采用头插法来实现:
直到cur==nullptr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution { public: ListNode* reverseList(ListNode* head) { ListNode *pre = nullptr; ListNode *cur = head; while(cur != nullptr){ ListNode *t = cur->next; cur->next = pre; pre = cur; cur = t; } return pre; } };
|
给你单链表的头指针 head
和两个整数 left
和
right
,其中 left <= right
。请你反转从位置
left
到位置 right
的链表节点,返回 反转后的链表
。
示例:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
思路:
方法一:递归
在解决这道题之前。如果需要我们只反转开头的前m
个元素,我们如何解决呢?
例如:
reverse(head, 3)
思路和我们前面一题反转全部链表差不多,我们只需要记录反转的节点个数即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ListNode *succ = nullptr;
ListNode* reverseN(ListNode *head, int n){ if(n == 1){ succ = head->next; return head; } ListNode *last = reverseN(head->next, n - 1); head->next->next = head; head->next = succ; return last; }
|
现在我们再来解决这道题,如果left = 1
,也就是我们刚才实现的功能。
如果 left != 1
怎么办?如果我们把 head
的索引视为 1,那么我们是想从第 left
个元素开始反转对吧;如果把 head->next
的索引视为 1
呢?那么相对于 head->next
,反转的区间应该是从第
left - 1
个元素开始的;那么对于
head->next->next
呢……
区别于迭代思想,这就是递归思想,所以我们可以完成代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution { public: ListNode *succ = nullptr;
ListNode* reverseN(ListNode *head, int n){ if(n == 1){ succ = head->next; return head; } ListNode *last = reverseN(head->next, n - 1); head->next->next = head; head->next = succ; return last; } ListNode* reverseBetween(ListNode* head, int left, int right) { if(left == 1){ return reverseN(head, right); } head->next = reverseBetween(head->next, left - 1, right - 1); return head; } };
|
方法二:迭代
同样采用头插法,先找到left
节点的左边一个节点pre
将left
所在的节点定义为cur
,cur
下一个节点为next
- 把
cur
的下一个节点指向next
的下一个节点
- 把
next
的下一个节点指向pre
的下一个节点
- 把
pre
的下一个节点指向next
即
1 2 3 4
| next = cur->next; cur->next = next->next; next->next = pre->next; pre->next = next;
|
以此类推right - left
次:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public: ListNode* reverseBetween(ListNode* head, int left, int right) { ListNode *dummy = new ListNode(-1); dummy->next = head; ListNode *pre = dummy; 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 dummy->next; } };
|