【LeetCode练习】[困难]25. K 个一组翻转链表
25. K 个一组翻转链表
题目来源
算法思想:链表 翻转
题目:
思路:
- 划分成长度为k的组;
- 将每个组进行逆转;
- 注意每个组之间的连接
java代码–单纯链表翻转(迭代and递归)
迭代法:
//迭代法
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode p1 = head.next;//[head,p1,p2]指针顺序关系
ListNode p2 = p1.next;
head.next = null;
while (p2 != null) {
//p2非空时,将p1.next指向head;
p1.next = head;
head = p1;//三个指针,全部向后移
p1 = p2;
p2 = p2.next;
}//结束时,即p2为空,此时,p1指向最后一个节点,head指向p1前一个节点
p1.next = head;//将p1.next指向head
return p1;//返回p1,最后一个节点,此时链表翻转结束
}
}
递归法:
//递归法
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode p = reverseList(head.next);//p指向已经翻转好了的链表
head.next.next = head;//当前节点head的下一个结点next指向自己
head.next = null;//当前节点的下一个设置成null;
return p;//返回p,翻转好的
}
}
java代码–题解–迭代版
以上思路,具体实现如下:
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
boolean falg = false;
ListNode countListNode = head;//用来计数,连接
ListNode first = new ListNode(0);//头指针
ListNode prior = new ListNode(0);//连接
first.next = prior;
prior.next = head;
ListNode precount = prior;//用来连接
while (countListNode != null) {
for (int i = 0; i < k && countListNode != null; i++) {
//计数,看是否满足k
countListNode = countListNode.next;
precount = precount.next;
if (i == k-1) {
falg = true;//如果不满足,不进行逆转
}
}
if (falg) {
//如果满足,将<prior.next,precount>区间内的链表进行翻转
precount.next = null;//将链表最后一个改成null,方便调用函数
prior.next = reverse(prior.next);//调用函数进行逆转
precount = prior;//重新开始遍历翻转后的链表
for (int i = 0; i < k; i++) {
precount = precount.next;
}
precount.next = countListNode;//将翻转后的链表与剩下的链表进行连接
prior = precount;//将prior修改成没有翻转链表的前一位,进行下一轮翻转
falg =false;//下一轮翻转
}
}
return first.next.next;//返回
}
//给定一个链表,将其逆转(迭代)
public ListNode reverse(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode p1 = head.next;//[head,p1,p2]指针顺序关系
ListNode p2 = p1.next;
head.next = null;
while (p2 != null) {
//p2非空时,将p1.next指向head;
p1.next = head;
head = p1;//三个指针,全部向后移
p1 = p2;
p2 = p2.next;
}//结束时,即p2为空,此时,p1指向最后一个节点,head指向p1前一个节点
p1.next = head;//将p1.next指向head
return p1;//返回p1,最后一个节点,此时链表翻转结束
}
}
java代码–题解–递归版
leetcode显示这题如下递归写法效率很高,很巧妙;
思路:
- 在每次递归函数中实现k长度链表的翻转;
- 巧妙运用递归返回来实现k分组之间的连接;
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
int n = k;
ListNode temp = head;//用来移动计数,k个结点
//统计是否满足k,满足需要翻转,反之可以直接返回
while (temp != null && n > 0) {
temp = temp.next;
n--;
}//temp指向 head-k 结点的开始,即下一个要翻转链表的开始
//如果不满足k个,则不需要翻转,直接返回;
//如果翻转长度是1,也不需要翻转,直接返回
if(n != 0 || k == 1) {
return head;
}
//将head开始长度为k的链表进行翻转
n = k;
ListNode p1 = null;//[p1,p2,p3]三者关系,运用p2.next = p1来完成翻转,然后每个指针往后移一格;
ListNode p2 = head;
ListNode p3 = head;
while(n > 0){
//循环k次,即翻转k次
p3 = p3.next;//p3.向后移
p2.next = p1;//翻转操作
p1 = p2;//p1向后移
p2 = p3;//p2向后移
n--;
}
//到此,完成链表中head之后k个结点的翻转
//head指向翻转链表末尾;
//p1指向翻转链表头;
//实现连接:
//head.next:表示末尾的下一个结点
//reverseKGroup(temp, k):表示将temp指向的未翻转的链表进行翻转,并且返回翻转后的表头;
head.next = reverseKGroup(temp, k);//末尾的下一个指向翻转好的链表表头
return p1;//返回表头;
}
}