100道面试必会算法-10-K 个一组翻转链表
题目描述
给你链表的头节点 head
,每 k
个节点一组进行翻转,请你返回修改后的链表。
k
是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k
的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:
输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
解题思路
看完题目描述还是有思路的,本质上就是反转链表,只不过变成了k个一组,那么我只需要确定好k的位置,也就是尾指针处于第k位置,我把慢指针从头开始一边遍历一边翻转即可,首先得知道链表长度,因为最后一组不够k就不需要翻转,确定好需要满足k的循环个数,再遍历内部进行翻转即可,思路没毛病,也进行了事实,如下(非正确答案,有细节未处理):
上述感觉思路没毛病,并一直怀疑这道题为什么标为难
public ListNode reverseKGroup(ListNode head, int k) {
ListNode fast=head;
ListNode pre;
ListNode slow = head;
int n=0;
// 确定能分几组
while (fast.next!=null){
n++;
fast=fast.next;
}
n=n/k;
// 链表可划分n个k组
for (int i = 0; i < n; i++) {
int num=0;
pre=null;
// 对每个k组进行翻转
while (num!=k){
ListNode temp = slow.next;
// 将慢指针 slow 的下一个节点指向前驱节点 pre
slow.next = pre;
// 更新前驱节点 pre 为慢指针 slow
pre = slow;
// 更新慢指针 slow 为下一个节点
slow = temp;
num++;
}
}
//返回头节点
return head;
}
结果并不如我所想,又分析了正确答案,有一个细节忽略了,我在进行翻转时,上一组跟当前组断开了,没有进行链接
大意失荆州啊
更改后:
public ListNode reverseKGroup(ListNode head, int k) {
// 检查特殊情况
if (head == null || k <= 1)
return head;
// 创建一个虚拟头结点,方便操作
ListNode dummy = new ListNode(0);
dummy.next = head;
// 记录前一组的尾节点,初始化为虚拟头结点
ListNode prevGroupTail = dummy;
// 计算链表长度
int n = countNodes(head);
// 只要剩余节点数大于等于k,就继续分组反转
while (n >= k) {
// 取出当前分组的头节点
ListNode groupHead = prevGroupTail.next;
// 初始化反转过程中的前一节点为null
ListNode prev = null;
// 当前节点为分组头节点
ListNode curr = groupHead;
// 对当前分组的节点进行反转
for (int i = 0; i < k; i++) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
// 将前一组的尾节点指向当前分组的头节点
prevGroupTail.next = prev;
// 将当前分组的尾节点指向下一组的头节点
groupHead.next = curr;
// 更新前一组的尾节点为当前分组的头节点
prevGroupTail = groupHead;
// 更新剩余节点数
n -= k;
}
return dummy.next;
}
// 计算链表长度
private int countNodes(ListNode head) {
int count = 0;
while (head != null) {
count++;
head = head.next;
}
return count;
}
通过,也符合题目要求,增加了一丢丢面对难题的自信,以下为完整可直接idea运行代码:
/**
* @author 不负遇见
* @version 1.0
* @description: TODO
* @date 2024/3/23 18:19
*/
public class LC08 {
static class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
}
public ListNode reverseKGroup(ListNode head, int k) {
// 检查特殊情况
if (head == null || k <= 1)
return head;
// 创建一个虚拟头结点,方便操作
ListNode dummy = new ListNode(0);
dummy.next = head;
// 记录前一组的尾节点,初始化为虚拟头结点
ListNode prevGroupTail = dummy;
// 计算链表长度
int n = countNodes(head);
// 只要剩余节点数大于等于k,就继续分组反转
while (n >= k) {
// 取出当前分组的头节点
ListNode groupHead = prevGroupTail.next;
// 初始化反转过程中的前一节点为null
ListNode prev = null;
// 当前节点为分组头节点
ListNode curr = groupHead;
// 对当前分组的节点进行反转
for (int i = 0; i < k; i++) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
// 将前一组的尾节点指向当前分组的头节点
prevGroupTail.next = prev;
// 将当前分组的尾节点指向下一组的头节点
groupHead.next = curr;
// 更新前一组的尾节点为当前分组的头节点
prevGroupTail = groupHead;
// 更新剩余节点数
n -= k;
}
return dummy.next;
}
// 计算链表长度
private int countNodes(ListNode head) {
int count = 0;
while (head != null) {
count++;
head = head.next;
}
return count;
}
public static void main(String[] args) {
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);
LC08 lc08 = new LC08();
ListNode result = lc08.reverseKGroup(head, 2);
// 输出结果
while (result != null) {
System.out.print(result.val + " ");
result = result.next;
}
}
}
08.reverseKGroup(head, 2);
// 输出结果
while (result != null) {
System.out.print(result.val + " ");
result = result.next;
}
}
}
over!再接再励!!!