一、题目分析
1.1 getKGroupEndNode 获得第K个元素
getKGroupEndNode 方法入参start
是表示开始的位置,K
表示几个元素,返回的是从start
元素开始之后的第K
个元素。
1.2 reverse K个元素组内逆序处理
reverse
方法可以将一个组内的元素逆序排列,例如: 1 ——> 2 ——> 3 ——> 4
,start
为 1
,end
为 3
, 此时将end
的next
指针记录下来,新赋值为end
,即end
(3)向后移动一位(此时end=4),是为了可以将反转后的链表和之后的链表连接起来,链表反转后start
(1)元素此时为最后一位元素,将start
(1)的指针指向最开始end
的next
(4)位置。此时链表为
1 <—— 2 <—— 3 4
⬇️ ________________________ ⬆️
1.3 reverseKGroup 主程序
reverseKGroup
方法是实现该题目的主程序,入参为链表头节点head和K个元素为一组。
首选分析链表的元素是否能够按照K个元素分成第一组,如果不能直接返回原head头节点;
将第一组元素逆序处理,此时第一组的end
元素为链表的新头节点;此时的start
元素已经为第一组的最后一个元素了,将它标记为lastStart
。
二、代码实现
package com.lsh.day05;
/**
* @author :LiuShihao
* @date :Created in 2022/2/5 6:38 下午
* @desc :题目:K个节点的组内逆序调整
*/
public class Code05 {
/**
* 单链表结构
* @param <V>
*/
public static class ListNode<V>{
private V value;
private ListNode<V> next;
public ListNode(V date){
value = date;
next = null;
}
}
/**
* K个节点的组内逆序调整
* @param head
* @param K
* @return
*/
public static ListNode reverseKGroup(ListNode head,int K){
ListNode start = head;
//是否凑齐第一组
ListNode end = getKGroupEndNode(start, K);
if (end == null){
//队列中不到K个元素,不做处理,返回原head
return head;
}
//此时第一组的end逆序排列后成为整个队列的新头部
head = end;
reverse(start,end);
//上一组的start经过逆序后成为最后节点
ListNode lastStart = start;
while (lastStart.next != null){
//如果上一组的结尾节点的next节点不为空
start = lastStart.next;
end = getKGroupEndNode(start, K);
if (end == null){
//剩余的元素不够凑成一组,则不进行逆序处理,返回head。
return head;
}
reverse(start,end);
//注意:需要将上一组的结尾节点的next指针指向这一组的end节点 :才能将上一组和这一组连接起来。
lastStart.next = end;
//并且需要更新lastStart为这一组的start
lastStart = start;
}
//所有的元素都正好成组,所有组逆序处理后返回head。
return head;
}
/**
* 获得起始点后的第K个元素
* 1 2 3 4 null
* start 1 k = 5
* @param start
* @param K
* @return
*/
public static ListNode getKGroupEndNode(ListNode start,int K){
while ( --K != 0 && start != null){
start = start.next;
}
return start;
}
/**
* 组内逆序
* start end
* 1 -> 2 -> 3
* ---------------------------------
* start
* cur end = end.next
* 1 -> 2 -> 3 -> 4
* ---------------------------------
* 1 <- 2 <- 3 <- 4
* ↓ ↑
* |_________________|
* @param start 起始位置
* @param end 结束位置
* @return
*/
public static void reverse(ListNode start,ListNode end){
//先将end向后移动一位。
end = end.next;
ListNode pre = null;
ListNode cur= start;
ListNode next= null;
while (cur != end){
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
// cur 到达end位置结束循环,并且将start的next指针指向end(即当时end的next)
start.next = end;
}
}
三、验证
/**
* 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7
* 组内K个节点逆序
* 3 -> 2 -> 1 -> 6 -> 5 -> 4 -> 7
* @param args
*/
public static void main(String[] args) {
ListNode<Integer> 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);
head.next.next.next.next.next = new ListNode<>(6);
head.next.next.next.next.next.next = new ListNode<>(7);
ListNode newHead = reverseKGroup(head, 3);
while (newHead!= null){
System.out.print(newHead.value + " ");
newHead = newHead.next;
}
System.out.println();
}