leetcode-K 个一组翻转链表

601 阅读3分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

今天是8月16日,本月有31天,今天写完,这个月的活动也完成过半了。

这2周除了工作上,其他的事情都还挺好的,每天写一篇文章,每周锻炼5天,每次至少30分钟,立下的几个Flag都没有倒。最近看了一些二手车的短视频,发现一个特别明显的现象:越是高端的二手车买卖,越是平淡,人物也更加彬彬有礼,交易中也更有信任感;越是低端的二手车交易,故事越是曲折离奇,有很多坑,充满了尔虞我诈,情节的戏剧性很难让人相信这是真实发生的事情。其实仔细想想,可能是针对了2种不同的人群,底层的人更加爱看这些冲突,他们生活的世界里面,这样连环坑的事情也更加常见,符合他们的世界观;高层的人更加平和,更多是看看车,认识交易的人,有了信任感之后,交易是更加自然而然的结果。所以,当你自己想要抱怨的时候,可能更应该反思一下,是不是自己能量还不够足,层次还不够高,所以周边环境显得更加恶劣,向内归因提升自己,是跳出恶劣环境的艰难的路,同时也是最近的捷径。

想了这么多,继续刷题精进技术吧,今天做leetcode的第25题。

题目

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

进阶:
你可以设计一个只使用常数额外空间的算法来解决此问题吗?
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
 

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例 2:

25示例1.jpeg

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

25示例2.jpeg

示例 3:
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]

示例 4:
输入:head = [1], k = 1
输出:[1]

思路

分成长度为k的小链表,最后1个分组可能会不足k个。对这k个小链表,做完全反转,然后再收尾相接起来,最后不足k个的小链表,不用反转,直接追加在最后面。如下图所示 25_1.jpg

小链表自身完全反转的方法:

  1. 定义1个pre节点为空,定义1个current节点指向头节点
  2. 记录current的next节点为next
  3. current的next指向pre
  4. current作为pre,next作为current
  5. 循环2-4,直到链表结束 25_2.jpg 25_3.jpg

Java版本代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode dummy = new ListNode();
        ListNode tail = dummy;
        ListNode index = head;
        while (index != null) {
            if (hasKListNode(index, k)) {
                // 剩余大于等于k个节点
                // 记录现在小链表的头结点
                ListNode subHead = index;
                // index向后走k个节点
                for (int i = 0; i < k; i++) {
                    index = index.next;
                }
                // 反转小链表,tail的next指向新小链表的头节点
                tail.next = reverseKListNode(subHead, k);
                // 原小链表的头结点是最新结果链表的尾结点,就是最新的tail
                tail = subHead;
            } else {
                // 剩余不足k个节点
                // 当前尾结点的next指向剩余的头结点
                tail.next = index;
                break;
            }
        }
        return dummy.next;
    }

    /**
     * 是否包含k个节点
     *
     * @param index
     * @param k
     * @return
     */
    private static boolean hasKListNode(ListNode index, int k) {
        while (k-- > 0) {
            if (index == null) {
                return false;
            }
            index = index.next;
        }
        return true;
    }

    /**
     * 反转链表
     *
     * @param head
     * @param len
     * @return
     */
    private static ListNode reverseKListNode(ListNode head, int len) {
        ListNode pre = null;
        ListNode current = head;
        while (len-- > 0) {
            ListNode next = current.next;
            current.next = pre;
            pre = current;
            current = next;
        }
        // 此时pre是新的链表的头结点
        return pre;
    }
}