一.问题描述
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.
Follow up:
- Could you solve the problem in
O(1)
extra memory space? - You may not alter the values in the list's nodes, only nodes itself may be changed.
Example 1:
Input: head = [1,2,3,4,5], k = 2 Output: [2,1,4,3,5]
Example 2:
Input: head = [1,2,3,4,5], k = 3 Output: [3,2,1,4,5]
Example 3:
Input: head = [1,2,3,4,5], k = 1 Output: [1,2,3,4,5]
Example 4:
Input: head = [1], k = 1 Output: [1]
二.解题思路
题目的意思就是说一个长为n的链表,每k个一组,在这组内翻转链表,组合组之间的顺序还是要保持一直,如果链表长度不能整除k,那么剩余的链表顺序应该保持一致。
解决的思路也比较直观,可以开个数组,把一组子链表按顺序存储下来。对于每个子链表进行翻转,记录好头和尾,之后迭代到下一个子链表,翻转完后,让上一个子链表的尾指向现在子链表的头,重复直到数组处理完毕。
要注意一下最后一个子链表,如何长度小于k应该保持不变,不过这个应该在将链表存储为子链表数组的时候就应该标记好的,不用做特别的处理。
时间复杂度:O(N),空间复杂度:O(N/k).
比较有趣的是题目的follow-up,期待我们用O(1)空间和不改变链表节点的value,只改变它本身来解决这个问题,这也是面试的时候考官很容易问的follow-up,
解决思路也很简单,和上面类似,不过我们不把原来链表分割成子链表组,直接迭代处理链表,对遇到的链表,我们进行翻转,这时候就需要一个指针来记录迭代的链表的次数,达到k之后,说明我们已经翻转好了一个子链表。
下一步要做的就是,要把这个子链表和上个子链表相连接,即让上一个子链表的尾指向当前子链表的头,因为我们没有用一个数组来保存子链表,因此需要开变量来记录上个子链表的尾。
然后就是对于不足k的子链表的处理,我的做法是遇到的就翻转,如果发现子链表迭代完但是还不到k次,那就把当前链表再翻转一次,实现保持原样。
当然每一个子链表的连接除了迭代,也可以用递归实现。
递归:
递归的话重点的话就是确定递推式,即确定函数的返回变量以及结束条件。其实也很明显,我们从前往后递归,让递归函数返回当前子链表的头,然后让当前递归的子链表的尾指向子递归返回的头即可。
递归结束条件为当前处理的链表为None,说明链表处理完毕。
其实和迭代大同小异。
时间复杂度:O(N),空间复杂度:O(1).
三.源码
# O(N) Time and O(1) memory, 迭代
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
def reverseNode(ln,k):
i=0
tail=ln
pre=None
cur=ln
while i<k:
if not cur:
return reverseNode(pre,i)
ln=ln.next
cur.next=pre
pre=cur
cur=ln
i+=1
tail.next=None
return pre,tail,cur
if not head:return None
new_head=ListNode()
pre_tail=new_head
while head:
cur_head,cur_tail,head=reverseNode(head,k)
pre_tail.next=cur_head
pre_tail=cur_tail
return new_head.next
# O(N) Time and O(1) memory, 递归
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
def reverseNode(ln,k):
i,tail,pre,cur=0,ln,None,ln
while i<k:
if not cur:
return reverseNode(pre,i)
ln=ln.next
cur.next=pre
pre=cur
cur=ln
i+=1
tail.next=None
return pre,tail,cur
if not head:return None
cur_head,cur_tail,head=reverseNode(head,k)
cur_tail.next=self.reverseKGroup(head,k)
return cur_head