算法-链表每k位逆序

2020-07-28  本文已影响0人  zzq_nene

链表的每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;
    }
上一篇下一篇

猜你喜欢

热点阅读