链表的每K位逆序,其实主要的思路就是三个步骤:
1.找到k个节点的开始节点和结束节点,还有当前这k个节点的最后一个节点的下一个节点
2.对k个节点做链表反转
3.将当前k个节点反转后的最后一个节点定义为下一组k个节点的上一个节点,重新找到下一组k个节点的开始节点,并将反转后的k个节点链表重新与完整链表进行连接
public static ListNode reverseKListNode(ListNode head, int k) {
if (head == null) {
return null;
}
if (head.next == null) {
return head;
}
if (k < 2) {
return head;
}
// k个节点的最左边的上一个节点
ListNode pKLeft = null;
// k个节点的最右边的下一个节点
ListNode pKRight = null;
// k个节点的最左边节点,逆序之后在k个节点的最右边
ListNode kStart = head;
// k个节点的最右边节点,逆序之后在k个节点的最左边
ListNode kEnd = null;
// 遍历整个链表的当前节点
ListNode cur = head;
int count = 1;
while (cur != null) {
if (count == k) {
// 其实就是在第一组的时候,将第一组k个元素反转之后得到的元素末尾作为新的head
head = kEnd == null ? cur : head;
kEnd = cur;
// 当前这k个节点链表的最右边节点的下一个节点
pKRight = cur.next;
// 链表反转-找到前中后三个节点
// 反转后kPre依然是这k个节点链表的头节点
ListNode kPre = kStart;
ListNode kCur = kPre.next;
ListNode kNext = null;
while (kCur != pKRight) {
kNext = kCur.next;
kCur.next = kPre;
kPre = kCur;
kCur = kNext;
}
// TODO 将当前反转的k个节点链表重新与完整链表进行连接
// pKLeft是当前这k个节点链表的最左边的上一个节点
// kPre是当前k个节点反转后的头节点
// 将当前反转的k个节点链表的头部重新加入连接到完整链表中
// 其实PKLeft是当前个节点的最左边的上一个,而kPre是当前k个节点反转之后的第一个
// 此时需要将之前的k个和当前k个连接起来,所以要使用当前k个的最左边的上一个
// 与当前k个反转之后的第一个连接起来
if (pKLeft != null) pKLeft.next = kPre;
// 这k个节点反转之后,头节点变成了尾节点,那么kStart就变成了这k个节点的尾节点
// 所以指向下一个节点
// 将当前反转的k个节点链表的尾部重新与完整链表进行连接
// kStart是当前k个节点反转之后的最右边节点,让其next指向pKRight,是让当前k个节点与后续节点连接起来
kStart.next = pKRight;
// TODO 定义下一个k个节点链表的开始节点和其开始节点的前一个节点
// 需要进行下一次k个节点的链表反转,则之前k个节点反转之后的的尾巴节点就变成了pKLeft
// 将当前反转后的k个节点的尾巴节点变成下一个k个节点的开始节点的前一个节点
pKLeft = kStart;
// 这里可以直接写pKRight
// 定义下一个k个节点的开始节点
kStart = pKLeft.next;
count = 0;
cur = pKRight;
} else {
cur = cur.next;
}
count++;
}
return head;
}
网友评论