题目:25. Reverse Nodes in k-Group
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
Example:
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5
Note:
- Only constant extra memory is allowed.
- You may not alter the values in the list's nodes, only nodes itself may be changed.
题意:
给出一个单链表及一个正整数k,将单链表中每连续k个元素反转,如若最后不足k个则按原序输出,返回最终翻转后的结果。
分析:
一道leetcode中难度为hard的题目,解答此题时,受所给样例的干扰,没搞清楚题目直接按k位翻转做了,导致后面各种修改才得以实现。以下为解题时的第一思路及本题所提交的最佳思路。
- 首先进行了常规判断,若所给list为空或仅有一个元素 再或者 k为1,那么均可以直接返回list。
- 翻转列表常规思路 即使用单链表头插法即可,不过本题要求每k个元素进行翻转,那么就需要由相应的变换,比如每够k个元素时,采用头插法的头节点需要更换。因此,可分为两种情况:1)当前翻转个数如果不够k个,则直接进行头插入即可。2)当前位置之前已经进行了k个元素的翻转,那么这时就需要更新头插法的头节点指向。这里还有一点不同的是,最后不足k个的话,不需要翻转,因此 在此之前对所给链表拷贝了一份(newlist),以便保存后面剩余的有序部分,所以每翻转k个元素,在更新头节点时,同样需要对newlist的指向进行后移操作。
- 以上遍历完之后 判断是否需要处理有序部分。如果需要,则直接在结果上追加对应的有序部分,否则将剩余的翻转过后的元素追加到结果链表上。
最佳解法
首先统计单链表的个数,然后先判断当前剩余的个数是否足够k个,足够则进行翻转,否之可以直接返回结果。
Code1 & C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if(head==NULL || head->next==NULL || k==1) return head;
ListNode *first = head->next, *end = head;
ListNode *pre = new ListNode(0), *newlist=new ListNode(0), *ans = new ListNode(0);
ListNode *p = newlist;
while(end!=NULL){ // 拷贝原始链表
ListNode *tmp = new ListNode(end->val);
p->next = tmp;
p = tmp;
end = end->next;
}
end = head;
newlist = newlist->next;
int i=1;
pre->next = head;
end->next = first;
ans = pre;
head = ans;// head 指向一个新建的结果链表
while(first!=NULL){
if(i<k){ // 正常翻转
ListNode *tmp = first;
first = first->next;
end->next=first;
tmp->next = pre->next;
pre->next = tmp;
++i;
}else{
i=1;
ans->next = pre->next; //将上一步翻转后的链表追加到结果链表上
ans = end;
pre = end; //更新头节点
end = first;
first = first->next;
int j=0;
while(j<k && newlist!=NULL){ // 有序链表同步后移
newlist = newlist->next;
j+=1;
}
}
}
if(i<k){ // 最后不足k个元素,将对应的有序部分追加到结果上
ans->next = newlist;
}else{
ans->next = pre->next; // 足够k个翻转,需要将最后一次翻转后的元素 追加到结果链表上来
ans = end;
}
return head->next;
}
};
结果:
Runtime: 24 ms, faster than 100.00% of C++ online submissions for Reverse Nodes in k-Group.
Memory Usage: 11 MB, less than 5.02% of C++ online submissions for Reverse Nodes in k-Group.
虽然以上解法,在leetcode提交中给到了100%的结果,但可见此解法逻辑之混乱,代码之冗余。分析原因主要还是对链表的操作不是很熟,导致各种胡拼乱凑,这里之所以将代码贴出来,主要是希望能够起到一个抛砖引玉出的作用。
Code2 & C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode dummy(-1);
ListNode *pre = &dummy, *cur = head;
dummy.next = head;
int num = 0;
while(cur){
++num;
cur = cur->next;
}
while(num>=k){
cur = pre->next;
for(int i=1;i<k;++i){
ListNode *tmp = cur->next;
cur->next = tmp->next;
tmp->next = pre->next;
pre->next = tmp;
}
pre = cur;
num -= k;
}
return dummy.next;
}
};
结果:
Runtime: 20 ms, faster than 100.00% of C++ online submissions for Reverse Nodes in k-Group.
Memory Usage: 10.3 MB, less than 39.00% of C++ online submissions for Reverse Nodes in k-Group.
很明显可以发现,第二种解法思路很清晰。另外还可以发现两种解法虽然时间不同,却给出了同样的成绩,可见leetcode的后台判定有些不稳定- 。-!!
Code2 & Python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
p = head
num = 0
while p!=None:
num+=1
p = p.next
pre = ListNode(-1)
pre.next = head
ans = pre
while num>=k:
cur = pre.next
for i in range(1,k):
tmp = cur.next
cur.next = tmp.next
tmp.next = pre.next
pre.next = tmp
pre = cur
num-=k
return ans.next
结果:
Runtime: 56 ms, faster than 70.70% of Python3 online submissions for Reverse Nodes in k-Group.
Memory Usage: 14.2 MB, less than 5.33% of Python3 online submissions for Reverse Nodes in k-Group.