码迷,mamicode.com
首页 > 其他好文 > 详细

025k个一组翻转链表

时间:2019-03-13 19:44:44      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:返回   结束   解答   原来   原理   变化   例子   ret   next   

  1 #include "000库函数.h"
  2 
  3 
  4 
  5 struct ListNode {
  6     int val;
  7     ListNode *next;
  8     ListNode(int x) : val(x), next(NULL) {}
  9 };
 10 /************************自己解答****************************/
 11  //不含头结点,链表中的数据按照k个k个地翻转,使用栈进栈出原理
 12 class Solution {
 13 public:
 14     ListNode* reverseKGroup(ListNode* head, int k) {
 15         if (k <= 1 || !head || !(head->next))return head;
 16         ListNode* Res = new ListNode(0);
 17         ListNode* r = Res;
 18         ListNode* p = head;
 19         stack<int> S;
 20         while (p) {
 21             S.push(p->val);            
 22             p = p->next;            
 23             if (S.size() == k) {
 24                 while (!S.empty()) { //采用尾插法
 25                     ListNode* q = new ListNode(0);
 26                     q->val = S.top();
 27                     r->next = q;
 28                     r = q;
 29                     S.pop();
 30                 }                
 31             }
 32         }
 33         if (S.size()) {
 34             while (!S.empty()) {            //采用头插法
 35                     ListNode* q = new ListNode(0);
 36                     q->val = S.top();
 37                     q->next = r->next;
 38                     r->next = q;                    
 39                     S.pop();                
 40             }
 41         }
 42         return Res->next;
 43 
 44     }
 45     
 46 };
 47 
 48 
 49 
 50 
 51 /*******************************博客答案***************************/
 52 //这道题让我们以每k个为一组来翻转链表,实际上是把原链表分成若干小段,
 53 //然后分别对其进行翻转,那么肯定总共需要两个函数,一个是用来分段的,
 54 //一个是用来翻转的,我们就以题目中给的例子来看,对于给定链表1->2->3->4->5,
 55 //一般在处理链表问题时,我们大多时候都会在开头再加一个dummy node,因为翻转链表时头结点可能会变化
 56 //为了记录当前最新的头结点的位置而引入的dummy node,那么我们加入dummy node后的链表变为
 57 //- 1->1->2->3->4->5,如果k为3的话,我们的目标是将1, 2, 3翻转一下,那么我们需要一些指针
 58 //,pre和next分别指向要翻转的链表的前后的位置,然后翻转后pre的位置更新到如下新的位置:
 59 
 60 
 61 
 62 //复制代码
 63 //- 1->1->2->3->4->5
 64 //|        |  |
 65 //pre      cur next
 66 //
 67 //- 1->3->2->1->4->5
 68 //|     |  |
 69 //cur   pre next
 70 //复制代码
 71 
 72 
 73 //以此类推,只要cur走过k个节点,那么next就是cur->next,
 74 //就可以调用翻转函数来进行局部翻转了,注意翻转之后新的cur和pre的位置都不同了,
 75 //那么翻转之后,cur应该更新为pre->next,而如果不需要翻转的话,cur更新为cur->next,
 76 
 77 
 78 
 79 //解法一://耗时超过自己的解答
 80 
 81 class Solution {
 82 public:
 83     ListNode* reverseKGroup(ListNode* head, int k) {
 84         if (!head || k == 1) return head;
 85         ListNode *dummy = new ListNode(-1), *pre = dummy, *cur = head;
 86         dummy->next = head;//添加头结点
 87         for (int i = 1; cur; ++i) {
 88             if (i % k == 0) {
 89                 pre = reverseOneGroup(pre, cur->next);
 90                 cur = pre->next;
 91             }
 92             else {
 93                 cur = cur->next;
 94             }
 95         }
 96         return dummy->next;
 97     }
 98     ListNode* reverseOneGroup(ListNode* pre, ListNode* next) {
 99         ListNode *last = pre->next, *cur = last->next;
100         while (cur != next) {
101             last->next = cur->next;
102             cur->next = pre->next;
103             pre->next = cur;
104             cur = last->next;
105         }
106         return last;
107     }
108 };
109 
110 
111 
112 //我们也可以在一个函数中完成,我们首先遍历整个链表,统计出链表的长度,
113 //然后如果长度大于等于k,我们开始交换节点,当k = 2时,每段我们只需要交换一次,
114 //当k = 3时,每段需要交换2此,所以i从1开始循环,注意交换一段后更新pre指针,然后num自减k
115 //直到num < k时循环结束,参见代码如下:
116 
117 
118 
119 //解法二:时间更长!!!!
120 
121 
122 class Solution {
123 public:
124     ListNode* reverseKGroup(ListNode* head, int k) {
125         ListNode *dummy = new ListNode(-1), *pre = dummy, *cur = pre;
126         dummy->next = head;
127         int num = 0;
128         while (cur = cur->next) ++num;
129         while (num >= k) {
130             cur = pre->next;
131             for (int i = 1; i < k; ++i) {
132                 ListNode *t = cur->next;
133                 cur->next = t->next;
134                 t->next = pre->next;
135                 pre->next = t;
136             }
137             pre = cur;
138             num -= k;
139         }
140         return dummy->next;
141     }
142 };
143 
144 
145 
146 //我们也可以使用递归来做,我们用head记录每段的开始位置,cur记录结束位置的下一个节点,
147 //然后我们调用reverse函数来将这段翻转,然后得到一个new_head,原来的head就变成了末尾,
148 //这时候后面接上递归调用下一段得到的新节点,返回new_head即可,参见代码如下:
149 
150 
151 class Solution {
152 public:
153     ListNode* reverseKGroup(ListNode* head, int k) {
154         ListNode *cur = head;
155         for (int i = 0; i < k; ++i) {
156             if (!cur) return head;
157             cur = cur->next;
158         }
159         ListNode *new_head = reverse(head, cur);
160         head->next = reverseKGroup(cur, k);
161         return new_head;
162     }
163     ListNode* reverse(ListNode* head, ListNode* tail) {
164         ListNode *pre = tail;
165         while (head != tail) {
166             ListNode *t = head->next;
167             head->next = pre;
168             pre = head;
169             head = t;
170         }
171         return pre;
172     }
173 };
174         
175 
176 void T025() {
177     ListNode* N = new ListNode(0);
178     ListNode* p = N;
179     for (int i = 0; i < 5; ++i) {
180         ListNode* q = new ListNode(0);
181         q->val = i + 1;
182         p->next = q;
183         p = q;
184     }
185     p = N->next;
186     cout << "原:";
187     while (p) {
188         cout << p->val << \t;
189         p = p->next;
190     }
191     cout << endl;
192     Solution S;
193     p = S.reverseKGroup(N->next,3);
194     cout << "转:";
195     while (p) {
196         cout << p->val << \t;
197         p = p->next;
198     }
199     cout << endl;
200     
201 
202 }

 

025k个一组翻转链表

标签:返回   结束   解答   原来   原理   变化   例子   ret   next   

原文地址:https://www.cnblogs.com/zzw1024/p/10525118.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!