算法 - k个一组翻转链表
题目描述:
- 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
- k 是一个正整数,它的值小于或等于链表的长度。
- 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
算法思路:区间翻转
- 思路:每次反转将链表分成三部分,翻转中间链表再拼接
头 - 前驱 | 开始 - 结束 | 后继 - NULL - 特殊点:要求当不足k个时需要保留原值—>不足k个可以放弃翻转,直接退出
判定策略:每次向后遍历k个结点,确定一个结束位置- 若结束位置为null,则剩余不足k个
- 若结束点不为null,则至少满足k个
代码中参数理解:
原链表:1 - 2 - 3 - 4 - 5 - null
要求:每个数字表示一个节点,若2个结点一反转
首先创建一个节点O作为前驱:
O - 1 - 2 - 3 - 4 - 5 - null
第一次反转前两个节点:1,2,遍历后参数指向情况
pre -> O --------- 反转区间的前一个
start -> 1 --------- 反转区间的开始
end -> 2 --------- 反转区间的结束
next -> 3 --------- 反转区间的后继
反转区间为:[start, end],反转后的结果是:2 -> 1,返回的节点是2
通过拼接链表实现反转后链表和原链表的连接
start -> 1,此时就是反转链表尾部,故:start.next = next;
结果:2 - 1 - 3 - 4 - 5 - null
pre -> O,此时就是反转链表的前驱,故:pre.next = 2
结果:O - 2 - 1 - 3 - 4 - 5 - null
具体边界值判定建议参考代码
/**
* 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) {
if (head == null) return null;
ListNode top = new ListNode(0);
top.next = head;
//设定操作的基础变量
ListNode pre = top;//反转区间前驱
ListNode end = top;//反转区间结尾
ListNode start = null;//反转区间开始
ListNode next = null;//反转区间的后继
int count = 0;//向后遍历的节点个数
while (end.next != null){
count = k;
while (count-- > 0 && end != null)
end = end.next;
if (end == null)
break;
start = pre.next;
next = end.next;
end.next = null;//设置翻转区间的结束位置
pre.next = reserve(start);//将翻转链表的头连接到翻转区间的前一个位置
start.next = next;//翻转后的链表尾部连接到链表为下一个
pre = start;//新的翻转区间的前驱就是上次翻转的结束
end = pre;//重置新的起始位置
}
return top.next;
}
/**
翻转算法,思路简单,当curr为null,则已经反转到了链表结尾
*/
public ListNode reserve(ListNode head){
ListNode pre = null;
ListNode curr = head;
ListNode next = null;
while (curr != null){
next = curr.next;
curr.next = pre;
pre = curr;
curr = next;
}
return pre;
}
}