25. K 个一组翻转链表

关于单链表倒置。有了单链表倒置,这道题无非就是用一个循环,每次将 k 个结点取下来,倒置后再接回去,然后再取 k 个,以此循环,到了最后一组如果不足 k 个,不做处理,直接返回头结点就可以了。所以关键就是,指针指来指去,大家不晕掉就好,我做了图示,大家参考一下。

为了将头结点也一般化,我们创建一个 dummy 结点,然后整个过程主要运用三个指针, tail 指针表示已经倒置后的链表的尾部,subhead 指针表示要进行倒置的子链表,toNull 指针为了将子链表从原来链表中取下来。

一个 while 循环,让 toNull 指针走 k - 1 步使其指向子链表的尾部。中间的 if 语句就是判断当前节点数够不够 k 个了,不够的话直接返回结果就可以了。

将子链表指向 null ,脱离出来。并且用 temp 保存下一个结点的位置。

然后调用倒置函数,将子链表倒置。

接下来四步分别是,新链表接到 tail(注意下边的图 tail 是更新后的位置,之前 tail 在 dummy 的位置) 的后边;更新 tail 到新链表的尾部,也就是之前的 subhead (下图 subhead 也是更新后的位置,之前的位置参见上边的图);sub_head 更新到 temp 的位置;toNull 到 sub_head 的位置;然后将新的尾部 tail 把之前断开的链表连起来,接到 sub_head 上。

整理下其实就是下边的样子

和初始的时候(下边的图)对比一下,发现 tail,subhead 和 toNull 三个指针已经就位,可以愉快的重复上边的步骤了。

看下代码吧。

public ListNode reverseKGroup(ListNode head, int k) {

if (head == null)

return null;

ListNode sub_head = head;

ListNode dummy = new ListNode(0);

dummy.next = head;

ListNode tail = dummy;

ListNode toNull = head;

while (sub_head != null) {

int i = k;

//找到子链表的尾部

while (i - 1 > 0) {

toNull = toNull.next;

if (toNull == null) {

return dummy.next;

}

i--;

}

ListNode temp = toNull.next;

//将子链表断开

toNull.next = null;

ListNode new_sub_head = reverse(sub_head);

//将倒置后的链表接到 tail 后边

tail.next = new_sub_head;

//更新 tail

tail = sub_head; //sub_head 由于倒置其实是新链表的尾部

sub_head = temp;

toNull = sub_head;

//将后边断开的链表接回来

tail.next = sub_head;

}

return dummy.next;

}

public ListNode reverse(ListNode head) {

ListNode current_head = null;

while (head != null) {

ListNode next = head.next;

head.next = current_head;

current_head = head;

head = next;

}

return current_head;

}

时间复杂度:while 循环中本质上我们只是将每个结点访问了一次,加上结点倒置访问的一次,所以总共加起来每个结点其实只访问了 2 次。所以时间复杂度是 O(n)。

空间复杂度:O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值