一.题目描述
NC50链表中的节点每k个一组翻转
题目链接:
https://www.nowcoder.com/practice/b49c3dc907814e9bbfa8437c251b028e?tpId=196&&tqId=37080&rp=1&ru=/activity/oj&qru=/ta/job-code-total/question-ranking
给出一个链表,每 k个节点为一组进行翻转,并返回翻转后的链表。k是一个正整数,它的值小于或等于链表的长度。如果节点总数不是k的整数倍,那么将最后剩余节点保持原有顺序。
示例:
二.算法(暴力模拟)
链表操作多复杂,直接用vector可以使代码简化。
- 遍历一遍链表,把链表的数值全部存到vector里面
- 每当添加了k个,局部进行一次翻转,利用revserse函数:reverse(左边位置,右边位置)
- 最后再把数组内的值赋给链表
下面直接上代码:class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { if(k==1) return head;//要是k=1 直接原数组不发生改变 ListNode *cur=head;//利用一个新指针去更新 vector<int> v; int count=0, index=0; while(cur){ v.push_back(cur->val); count++; index++; if(count==k){ //当计数器是k表示链表需要翻转 利用reverse函数翻转 reverse(v.begin()+index-k, v.begin()+index); //计数器清零 count = 0; } //指针后移 cur=cur->next; } cur=head; //最后返回是指针 对指针值进行从新赋值 for(int i=0;i<v.size();i++){ cur->val=v[i]; cur=cur->next; } return head; } };
时间复杂度:O(n)
空间复杂度:O(n)需要开辟vector来存储数
优缺点:实现简单,但是空间消耗大
三.算法(递归)
首先,我们要实现一个reverse函数反转一个区间之内的元素。在此之前我们再简化一下,在给定头节点的情况下对链表进行反转。
// 反转以 a 为头结点的链表 ListNode reverse(ListNode a) { ListNode pre, cur, nxt; pre = null; cur = a; nxt = a; while (cur != null) { nxt = cur.next; // 逐个结点反转 cur.next = pre; // 更新指针位置 pre = cur; cur = nxt; } // 返回反转后的头结点 return pre; }
反转以a为头结点的链表其实就是反转a到null之间的结点,那么反转a到b之间的结点就只需要吧null改为b是不是就可以实现了?下面给出反转a到b之间节点的代码:
/** 反转区间 [a, b) 的元素,注意是左闭右开 */ ListNode reverse(ListNode a, ListNode b) { ListNode pre, cur, nxt; pre = null; cur = a; nxt = a; // while 终止的条件改一下就行了 while (cur != b) { nxt = cur.next; cur.next = pre; pre = cur; cur = nxt; } // 返回反转后的头结点 return pre; }
现在我们迭代实现了反转部分链表的功能,那么只需要遍历种反转链表不就是可以了么,下面是完整代码:
class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { auto node=head; for (int i=0;i<k;i++) { if (!node) return head; node = node->next; } auto res = reverse(head, node); // 翻转长度是k的链表 head->next = reverseKGroup(node, k); // 递归处理下一个长度是k的链表 return res; //返回头指针 } private: //reverse函数实现反转a到b之间的结点 ListNode* reverse(ListNode* left, ListNode* right) { auto pre=right; while (left!=right) { auto node=left->next; left->next=pre; pre = left; left = node; } return pre; } };
时间复杂度:O(n)
空间复杂度:O(1) 没有使用额外空间
优缺点:时间复杂度低,但是思考过程难 不容易向到