92. Reverse Linked List II (补全)

仅供自己学习

 

思路:

这里先使用的是递归的方法,首先是反转整个的链表,在判断已经递归到最后一个元素后,将该元素作为新的头节点,返回该元素,我们在倒数第二个元素,现在将这个元素的next的next指向该元素,再将该元素的next指向NULL,然后再次返回头节点,再次进行。

例如1->2->3->4,我们返回4,作为翻转后的头结点,我们在3,将3->next->next=3,即4->next=3,4->3,然后3->next=NULL,那么此时是 1->2->3->NULL,而此时4又指向3。再次返回头节点4,在重复以上步骤,2->next->next=2,2->next=NULL,那么就是1->2->NULL,4->3->2->null。一直重复即可。

代码

1 ListNode* reverse(ListNode* head){ 
2         if(head->next==NULL) return head;
3         ListNode* last = reverse(head->next);
4         head->next->next=head;
5         head->next=back;
6         return last;
7     }

如果是前n个反转呢

那么我们需要一个来记录第n+1个的位置,然后其余的是不变的。

1     ListNode* back =NULL;
2     ListNode* reverse(ListNode* head,int n){
3         if(n==1) { back=head->next; return head;}  //分到n=1后,就是前n个最后的一个节点了,那么记录后面的节点的位置,返回该节点作为反转头节点,其余不变
4         ListNode* last = reverse(head->next,n-1);  //每次后退一个元素,那么从该元素开始到n,就应该减1,就是前n-1个反转,一直分,分到最小的n=1后
5         head->next->next=head;
6         head->next=back;
7         return last;
8     }

 

那如果是反转 第m到n个元素呢。

同样当m=1是,就是反转前n个元素了

那么同样是递归将m~n不断分小,每次递归传入的是head->next,left-1,right-1。因为我们传入的是next下一个元素,那么以他为链表的新起点,对他来说第left的元素的下标应该-1,第right元素的下标也会-1.那么我们递归一直到head的位置为left为止,那么就变成了前right个元素来反转。所以当我们的left-1减到1后,就调用反转前n个元素的代码,然后这个函数调用完后,那么left~right之间的节点就反转完成,那么直接返回这个函数返回的翻转后链表的头节点,因为这个返回是赋值给head->next就相当于直接更新了连接反转区间的那个元素的next。 

如:1->2->3->4->5,left=2,right=4,那么我们递归head->next=reverseBetween(head->next,left-1,right-1); 然后就是在2->3->4->5这个链表中 从left=1,right=3这个范围进行翻转,调用前n个元素反转的代码后得到 4->3->2->5,然后将这个翻转后的链表的头节点4返回给1->next那么就得到1->4->3->2->5

 

代码:

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode() : val(0), next(nullptr) {}
 7  *     ListNode(int x) : val(x), next(nullptr) {}
 8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 9  * };
10  */
11 class Solution {
12 public:
13     ListNode* back =NULL;
14     ListNode* reverse(ListNode* head,int n){
15         if(n==1) { back=head->next; return head;}
16         ListNode* last = reverse(head->next,n-1);
17         head->next->next=head;
18         head->next=back;
19         return last;
20     }
21     ListNode* reverseBetween(ListNode* head, int left, int right) {
22         if(left==1){
23             return reverse(head,right);
24         }
25         head->next=reverseBetween(head->next,left-1,right-1);
26         return head;
27     }
28 };

 

还有一种迭代的方法。就是移动到left后开始反转。

 

首先我们需要定义一个虚拟头结点,因为如果left为1,第一个节点也要反转,但是head并不会还指向反转后的第一个元素,而是继续指向反转前的第一个节点。所以如果用一个虚拟节点指向head,那么当head也要反转的时候,还能通过虚拟节点指向真正的链表。

 

我们用三个指针,pre,用来指向反转区间的左边缘节点的前一个结点;cur刚开始用来指向反转区间的做边缘节点,反转后会跟着移动到下一个节点,而back指针用来指向cur的下一个节点,辅助操作能使反转更为方便。

 

刚开始将虚拟节点 dummy->next指向head,然后pre指向dummy,因为如果pre指向dummy根据后边反转的代码,可以让反转后的链表头节点被dummy->next所指。然后移动pre到left-2的位置。然后开始反转。

 

首先将 back指向cur->next,再将cur->next=back->next,再将back->next指向pre->next(这里不是cur的原因是,当cur不断移动后,cur一直指向的是这个节点,如果写的cur就会一直指的同一个节点了,只是这个节点一直在后移),最后pre->next=back。

如 dummy->9->7(pre)->2(cur)->5(back)->4->3->6. 反转区间为【3,6】。 cur->next=back->next,dummy->9->7(pre)->2(cur)->4->3->6,但此时 还有->5(back)->4->3->6。back->next指向pre->next,dummy->9->7(pre)->2(cur)->4->3->6还有5(back)->2(cur)。pre->next=back,就是dummy->9->7(pre)->5(back)->2(cur)->4->3->6,这样就将5和2翻转,同样会对之后的进行这样反转。还能看到cur仍然指向2节点,如果下一步back->next不是指向pre->next,而是cur,那么就错误了。

代码:

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode() : val(0), next(nullptr) {}
 7  *     ListNode(int x) : val(x), next(nullptr) {}
 8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 9  * };
10  */
11 class Solution {
12 public:
13     ListNode* reverseBetween(ListNode* head, int left, int right) {
14         ListNode* dummy=new ListNode(-1);
15         dummy->next=head;
16         ListNode* pre=dummy;
17         for(int i=0;i<left-1;++i){
18             pre=pre->next;
19         }
20         ListNode* cur = pre->next;
21         ListNode* back = NULL;
22         for(int i=0;i<right-left;++i){
23             back=cur->next;
24             cur->next=back->next;
25             back->next=pre->next;
26             pre->next=back;
27         }
28         return dummy->next;
29     }
30 };

 

posted @ 2021-03-29 00:31  Mrsdwang  阅读(39)  评论(0编辑  收藏  举报