更多 LeetCode 题解笔记可以访问我的 github

描述

给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。

示例 :

给定这个链表:1->2->3->4->5

k = 2 时,应当返回: 2->1->4->3->5

k = 3 时,应当返回: 3->2->1->4->5

说明 :

  • 你的算法只能使用常数的额外空间。
  • 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

解法一:迭代

思路

要求解这道题,先要构造一个辅助函数,这个函数的作用就是翻转链表(不包括首尾节点)。假设输入链表如下图所示,其中链表表头为 begin,链表尾部为 end

经过函数之后,链表的连接变为如下的形式,且将 begin 作为函数的输出。

具体的实现思路和 LeetCode 第206题翻转链表是一致的,只是函数的输入和输出有些不同,这里不在赘言,直接给出函数的实现。

// Java 版本
private ListNode reverse(ListNode begin, ListNode end) {
ListNode prev = begin, curr = begin.next;
ListNode first = curr;
while (curr != end) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
begin.next = prev;
first.next = curr;
return first;
}
# Python 版本
def reverse(begin, end):
prev, curr, first = begin, begin.next, begin.next
while curr != end:
curr.next, prev, curr = prev, curr, curr.next
begin.next, first.next = prev, curr
return first

有个上面的辅助函数之后,我们就可以利用它求解这道题。假设输入链表为 1 -> 2 -> 3 -> 4 -> 5k=3,首先构造一个虚拟头节点 dummy,用于统一后面的一系列操作。初始时,设变量 i=0,当 i+1 不能被3整除时,将 head 指针向链表的下一个节点移动;当 i+1 能被3整除时,调用上面的辅助函数,将 begin 节点和 head.next 节点之间的节点进行翻转。具体的操作可以看下面的图片演示。

之后,将 head 指针指向 begin 指针的下一个节点(这里为 4),即 head = begin.next。如此循环往复,直到 head 节点为 null,则结束所有操作。

Java 实现

/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
// boundary judgement
boolean hasNoOrOneNode = (head == null || head.next == null);
if (hasNoOrOneNode || k == 1) {
return head;
} ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode begin = dummy;
int i = 0;
while (head != null) {
++i;
if (i % k == 0) {
begin = reverse(begin, head.next);
head = begin.next;
} else {
head = head.next;
}
}
return dummy.next;
} private ListNode reverse(ListNode begin, ListNode end) {
ListNode prev = begin, curr = begin.next;
ListNode first = curr;
while (curr != end) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
begin.next = prev;
first.next = curr;
return first;
}
}
// Runtime: 3 ms
// Your runtime beats 100.00 % of java submissions.

Python 实现

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None class Solution:
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
has_no_or_one_node = (not head or not head.next)
if has_no_or_one_node or k == 1:
return head dummy = ListNode(-1)
dummy.next = head
begin = dummy
i = 0
while head:
i += 1
if i % k == 0:
begin = self._reverse(begin, head.next)
head = begin.next
else:
head = head.next
return dummy.next def _reverse(self, begin, end):
prev, curr, first = begin, begin.next, begin.next
while curr != end:
curr.next, prev, curr = prev, curr, curr.next
begin.next, first.next = prev, curr
return first

复杂度分析

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(1)\)

解法二:递归(不满足空间复杂度)

思路

递归的思路和迭代的思路是一样的,也是对 k 个为一组的节点进行翻转,区别在于递归是按照从后往前的顺序分别对每组节点进行翻转,而迭代则是从前往后。

Java 实现

/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode curr = head;
int i = 0;
while (curr != null && i < k) {
++i;
curr = curr.next;
} if (i == k) {
curr = reverseKGroup(curr, k);
while (i > 0) {
ListNode tmp = head.next;
head.next = curr;
curr = head;
head = tmp;
--i;
}
head = curr;
}
return head;
}
}

Python 实现

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None class Solution:
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
curr = head
i = 0
while curr and i < k:
curr = curr.next
i += 1 if i == k:
curr = self.reverseKGroup(curr, k)
while i > 0:
head.next, head, curr = curr, head.next, head
i -= 1
head = curr
return head

复杂度分析

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(n)\)

【LeetCode题解】25_k个一组翻转链表(Reverse-Nodes-in-k-Group)的更多相关文章

  1. [Swift]LeetCode25. k个一组翻转链表 | 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  ...

  2. [Leetcode] Reverse nodes in k group 每k个一组反转链表

    Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If ...

  3. Reverse Nodes In K Group,将链表每k个元素为一组进行反转---特例Swap Nodes in Pairs,成对儿反转

    问题描述:1->2->3->4,假设k=2进行反转,得到2->1->4->3:k=3进行反转,得到3->2->1->4 算法思想:基本操作就是链表 ...

  4. K组翻转链表 · Reverse Nodes in k-Group

    [抄题]: 给你一个链表以及一个k,将这个链表从头指针开始每k个翻转一下.链表元素个数不是k的倍数,最后剩余的不用翻转. [思维问题]: [一句话思路]: // reverse head->n1 ...

  5. [LintCode] Reverse Nodes in k-Group 每k个一组翻转链表

    Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If ...

  6. Java实现 LeetCode 25 K个一组翻转链表

    25. K 个一组翻转链表 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度. 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持 ...

  7. LeetCoded第25题题解--K个一组翻转链表--java--链表

    链表 单链表:链表中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素的引用字段链接在一起. 双链表:与单链表不同的是,双链表的每个节点都含有两个引用字段. 链表优点 灵活分配内存空间 能在O ...

  8. leetcode 25. K 个一组翻转链表

    # coding:utf-8 __author__ = "sn" """ 25. K 个一组翻转链表 给你一个链表,每 k 个节点一组进行翻转,请你返 ...

  9. LeetCode 25. K 个一组翻转链表 | Python

    25. K 个一组翻转链表 题目来源:https://leetcode-cn.com/problems/reverse-nodes-in-k-group 题目 给你一个链表,每 k 个节点一组进行翻转 ...

随机推荐

  1. ubuntu apache linux

    在ubuntu下安装的apache, 很多配置文件都分开写了,需要了解一下各部分: http://blog.csdn.net/veizz/article/details/7410784 Ubuntu下 ...

  2. node-lessons

    教程:https://github.com/alsotang/node-lessons 0 nvm 的全称是 Node Version Manager,之所以需要这个工具,是因为 Node.js 的各 ...

  3. brctl命令

    有五台主机.其中一台主机装有linux ,安装了网桥模块,而且有四块物理网卡,分别连接同一网段的其他主机.我们希望其成为一个网桥,为其他四台主机(IP分别为192.168.1.2 ,192.168.1 ...

  4. 最全面的Git 使用规范装逼指南[转载]

    <!DOCTYPE html> <script type="text/javascript"> window.logs = { pagetime: {} } ...

  5. [LintCode] Permutations II

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

  6. MicrosoftSQLServer数据库定时备份(备份计划)的几种方式

    首先,做备份计划钱,先要查看下SQL Server代理是否开启 进入主题 1.备份计划方式1: 1.1新增数据库备份作业: 备份脚本: declare @name varchar() ))+'.bak ...

  7. Python 生成器的使用(yield)

    一. 生成器就是一个特殊的迭代器, 使用关键字yield就可以生成一个生成器 def func(): for i in range(10): yield i item = func() yield i ...

  8. 启动HDFS之后一直处于安全模式org.apache.hadoop.hdfs.server.namenode.SafeModeException: Log not rolled. Name node is in safe mode.

    一.现象 三台机器 crxy99,crxy98,crxy97(crxy99是NameNode+DataNode,crxy98和crxy97是DataNode) 按正常命令启动HDFS之后,HDFS一直 ...

  9. Java代码调用Oracle的存储过程,存储函数和包

    Java代码调用存储过程和存储函数要使用CallableStatement接口 查看API文档: 上代码: java代码调用如下的存储过程和函数: 查询某个员工的姓名  月薪 职位 create or ...

  10. ubuntu安装ruby的几种方法总结

    1.apt-get安装 可以使用apt-cache查询功能,找到对应的可用的ruby版本. $ sudo apt-cache search ruby #这个结果很长,我只截取最后与ruby有关的部分 ...