• 模拟
      • 设置虚拟头结点
      • (当待翻转部分尾元素的下一个元素不为空时)循环的每次翻转K个元素
        • 确定待翻转部分的前驱结点,然后根据前驱结点确定待翻转部分的首结点尾结点后继结点
        • 翻转待翻转部分(虚拟头结点+待翻转部分)
        • 翻转后利用确定的四个结点将翻转部分与前面的已翻转部分和后面的未翻转部分连接起来。
        • 更新前驱结点,重置尾结点。(尾结点是重置后的尾结点(==前驱结点)K次循环确定的)
      • 如果根据前驱结点K次循环确定的待翻转部分尾结点为null,说明剩下元素不足K个,直接返回。
    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * ListNode *next;
    6. * ListNode() : val(0), next(nullptr) {}
    7. * ListNode(int x) : val(x), next(nullptr) {}
    8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
    9. * };
    10. */
    11. class Solution {
    12. public:
    13. ListNode* reverseKGroup(ListNode* head, int k) {
    14. ListNode *dummy = new ListNode(); // 虚拟头结点
    15. dummy->next = head;
    16. ListNode *pre = dummy; // 前驱结点
    17. ListNode *end = dummy; // 尾结点 每次重置为dummy,便于K次循环确定dummy。
    18. while (end->next != NULL) { // 尾结点的下一个结点为NULL->刚好翻转完整个链表
    19. // 通过前驱结点确定待翻转部分的首尾结点、后继结点
    20. ListNode *start = pre->next;
    21. for (int i = 0; i < k && end != NULL; i++) end = end->next;
    22. if (end == NULL) break; // 如果end为空,说明剩下元素不足K个,直接返回
    23. ListNode *next = end->next;
    24. end->next = NULL; // reverse结束的条件
    25. // 通过四个结点将刚翻转完的部分和前面已翻转的部分、后面未翻转的部分连接起来
    26. pre->next = reverse(start);
    27. start->next = next;
    28. // 更新前驱结点、清空尾结点。
    29. pre = start;
    30. end = pre;
    31. }
    32. return dummy->next;
    33. }
    34. ListNode *reverse(ListNode *node) {
    35. ListNode *pre = NULL;
    36. ListNode *cur = node;
    37. while (cur != NULL) {
    38. ListNode *tmp = cur->next;
    39. cur->next = pre;
    40. pre = cur;
    41. cur = tmp;
    42. }
    43. return pre;
    44. }
    45. };