【LeetCode练习】[困难]25. K 个一组翻转链表

【LeetCode练习】[困难]25. K 个一组翻转链表

25. K 个一组翻转链表

题目来源
算法思想:链表 翻转

题目:
在这里插入图片描述

思路:

  1. 划分成长度为k的组;
  2. 将每个组进行逆转;
  3. 注意每个组之间的连接

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显示这题如下递归写法效率很高,很巧妙;
在这里插入图片描述
思路:

  1. 在每次递归函数中实现k长度链表的翻转;
  2. 巧妙运用递归返回来实现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;//返回表头;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_39457586/article/details/109061890