[Leetcode] 25. Reverse Nodes in k-Group

原题链接: https://leetcode.com/problems/reverse-nodes-in-k-group/

1. 题目介绍

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.
给出一个链表,链表每k个节点,都要反转一次。
k是一个正整数,它小于等于链表的长度。如果链表的长度不是 k 的整数倍,那么链表最后剩余的小于k的部分顺序不变。
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.
只有常数级的额外存储空间。
你不能改变节点的val值,只能改变节点的连接。

2. 解题思路

这个题目是 206. Reverse Linked List92. Reverse Linked List II 的提高版本。

206. Reverse Linked List 需要反转全部链表。

92. Reverse Linked List II 需要反转链表的一小部分。

而本题则是每 k 个节点就需要反转一次,是对上面两题的拓展。

首先,我们需要掌握反转链表的工作。ListNode reverse(ListNode head , ListNode tail) 函数用于反转从cur 开始、到 tail 前结束(不包括tail)的节点。遍历需要反转的节点的同时,让每个节点的 next 值指向前一个节点就可以让链表反转了。

然后,我们需要控制反转链表的时机。我采用的方法是每走过 k 个节点,就调用一次反转链表的函数。反转链表的时候,第一个节点会被放到最后一个位置,所以需要记录这 k 个节点前面的节点pre,以便让 pre 接上反转后的第一个节点。同样,也需要记住这 k 个节点后的节点 afterK,保证连接后面的节点。

例如:

-1-> 1->2->3->4->5     k = 3

-1 是辅助头节点,需要反转的部分是 1->2->3
所以cur 是 1,tail 是 4 需要调用 reverse( 1 , 4 ) 用来反转 1->2->3
反转后是 -1 、 3 -> 2 -> 1 、 4 -> 5
还需要把 -1 和 3 接起来,1 和 4 接起来。
所以在反转之前,还需要记录 -1 和 4 的指针。也就是 pre 为 -1 ,afterK 为 4。

在这里特别说明一下,什么时候该用辅助头节点 -1 ,什么时候不需要用呢?
当链表原来的头节点可能会改变时,就需要使用辅助头节点
比如本题的情况,链表本身的头节点head可能会因为反转而被放到后面去。这时就需要使用辅助头节点进行操作。

实现代码

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
		if(head == null || head.next == null || k == 1){
			return head;
		}
		
		ListNode assist = new ListNode(-1);
		assist.next = head;
		
		ListNode cur = head; //cur指向当前节点
		ListNode pre = assist;//pre指向要反转的k个节点前面的节点
		
		for(int i = 1; cur != null ;i++){
			//如果i%k == 0,那么需要反转pre.next到cur之间的k个节点
			if(i % k == 0){
			//要反转的是pre.next到cur之间的k个节点,和cur后面的节点无关
			//因此需要对cur后面的节点保存
				ListNode afterK = cur.next;
			
			//pre.next在经过反转后,会成为k个节点中最后一个节点,需要保存
				ListNode Kth = pre.next;
			//pre.next指向反转后的新链表
				pre.next = reverse(pre.next,afterK);
				
				pre = Kth;//更新pre
				cur = afterK; //更新cur
			}
			//如果i%k != 0,则继续移动cur
			else{
				cur = cur.next;			
			}
		}
		
		return assist.next;
    }
    //反转从cur开始、到tail之前结束的节点(不包括tail)
    public ListNode reverse(ListNode head , ListNode tail){
        ListNode before = tail;
        
        while(head != tail){
            ListNode next = head.next;
            head.next = before;
            before = head;
            head = next;
        }
        return before;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值