链表编程专题--分组逆序链表

来源:互联网 发布:js正则表达式\s 编辑:程序博客网 时间:2024/06/05 06:42

1.题目

给定单向链表,以k个为一组,组内链表逆序,最后输出链表首节点。例如有单链表A->B->C->D->E->F->G->H,当k=3时,A->B->C逆序为C->B->A,同理D->E->F逆序为F->E->D,G->H逆序为H->G,最后链表就是C->B->A->F->E->D->H->G。

2.解法

因为要按k个一组,因此要有一个变量记录已经遍历了多少个,遍历到K个或者链表结束的时候,就要开始新的一组遍历。因每组的第一个结点逆序后都会成为该组的最后结点,也就是下一组第一个结点的前一个结点,因此要记录上一组的最初第一个结点是什么(暂且叫lastFirstNode),以便本组逆序结束后,能链接在lastFirstNode后,还要考虑每组第一个节点的next值要先赋空,不然逆序后会和第二个节点成环等问题,具体看代码及注释:

/** * Definition for singly-linked list. * public class ListNode { *     int val; *     ListNode next; *     ListNode(int x) { val = x; } * } */public static ListNode reverse(ListNode head, int k) {    if (head == null) {        return head;    }           ListNode firstNode = head;// 本组第一个结点    ListNode lastFirstNode = null;// 上组逆序前第一个结点    ListNode nowNode = head.next;// 正在遍历到的结点    ListNode finnalHead = head;// 最终输出的链表头    // 只有一个结点时,直接输出该节点即可    if (nowNode == null) {        return head;    }    ListNode nextNode = nowNode.next;// 正在遍历到的结点的下一个节点,可能为null    ListNode priousNode = head; // 正在遍历到的结点的前一个节点    // 因最终链表的头结点必然为第一组链表逆序后的首节点,因此设置一标志位以判定是否正在处理的是第一组链表    boolean firstK = true;     // 因最初正在遍历的结点我们设置的是第二个节点,因此无需遍历k次,而是k-1次。    // 此处需判断nowNode != null的原因是    for (int i = 0; i < k - 1 && nowNode != null; i++) {        nextNode = nowNode.next;        // 上组逆序结束后,会使firstNode和nowNode指向本组首节点,此时将nowNode指向后移,并做是否为空判断,        // 若为空,则说明本组只有一个结点,直接赋到上组逆序后的最后一个结点(也就是逆序前第一个节点)后即可        if (firstNode.equals(nowNode)) {            nowNode = nowNode.next;            if (nowNode == null) {                lastFirstNode.next = priousNode;                break;            }            nextNode = nowNode.next;        }        // 在遍历本组链表的开始时就需要将首节点的next值设为null,否则会出现和第二个节点成环的现象        if (i == 0) {            firstNode.next = null;        }        // 两个节点逆序        nowNode.next = priousNode;        // 将正在遍历的结点后移,这里就体现出保持下一个节点引用的作用了:        // 若不保持,则在逆序后,无法找到原本的下一个节点了。        priousNode = nowNode;        nowNode = nextNode;        // 如果遍历到本组最后的结点        if (i == k - 2 || nowNode == null) {            if (firstK == true) {                // 记录最终链表的首节点                finnalHead = priousNode;                firstK = false;            }            // 因在本次for循环结束后,i会自动加1,因此这里赋为-1,以便本次for循环结束后,i变为0            i = -1;            // 除第一组链表外,都需链接到上一组逆序后的链表末尾,因此这里对是否第一组做判断            if (lastFirstNode != null) {                lastFirstNode.next = priousNode;            }            // 将本组链表链接到上一组末尾后,将上组未逆序时首节点赋值为本组未逆序时首节点,            // 准备开始下一组的遍历逆序工作:此时nextNode指向的是下一组链表的第一个节点,            // firstNode和priousNode也都赋值为下一组第一个节点,            lastFirstNode = firstNode;            firstNode = nowNode;            priousNode = nowNode;        }    }    return finnalHead;}