K个一组反转单链表

K个一组反转单链表

题目

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
说明:
(1)k 是一个正整数,它的值小于或等于链表的长度。
(2)如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例如下所示:
在这里插入图片描述
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

解决思路

  • 方法:循环调用“基于递归法反转单链表”解决此题,递归法反转单链表请参考此博文的思路2:参考这里
  • 步骤:
    • 初始化:先创建一个虚拟头节点ret,再定义一个指针p指向虚拟头节点,再定义一个指针q指向p的下一个节点。
    • 反转节点1和节点2,所用方法:递归法反转单链。参考这里
    • 改变p、q指针的指向:使p指向q,q指向q的下一个节点。此时,从p的下一个节点开始的k个节点就是下一次要被反转的节点。
    • 反转节点3和节点4,所用方法:递归法反转单链。参考这里
    • 改变p、q指针的指向:p指向q,q指向q的下一个节点。此时,从p的下一个节点开始的k个节点就是下一次要被反转的节点。
    • 最后只剩下节点5没有被反转,因为剩下的节点数为1,小于设定的k值(设k=2),反转结束。

说明:

  • 指针p始终指向待反转部分的上一个节点。
  • 反转前指针q指向待反转部分的第一个节点,反转后指针q指向反转部分的尾结点。
  • 改变指针的指向后,指针p指向下一次要被反转部分的第一个节点的上一个节点,指针q指向下一次要被反转部分的第一个节点。

代码

  • C++代码:
# include <stdio.h>

struct ListNode {
    int val;
    ListNode *next;
    ListNode(): val(0), next(nullptr) {}
    ListNode(int val): val(val), next(nullptr) {}
    ListNode(int val, ListNode *next): val(val), next(next) {}
};


class Solution {
public:
    // 真正进行链表反转的操作(递归法反转单链表)
    ListNode *trueReverseN(ListNode *head, int num) {
        if (nullptr == head || nullptr == head->next || 1 == num) {
            return head;
        }
        
        ListNode *cur = head->next;
        ListNode *pre = trueReverseN(cur, num - 1);     // 指向反转后链表的头结点
        head->next = cur->next;
        cur->next = head;
        cur = cur->next;
        return pre;
    }

    // 先判断链表的长度够不够n个节点,如果够再进行反转。
    ListNode *reverseN(ListNode *head, int n) {
        if (nullptr == head || nullptr == head->next || 1 == n) {
            return head;
        }

        int cnt = n;
        ListNode *p = head;

        while (--n && p) {    // 判断链表的长度够不够n个节点。
            p = p->next;
        }
        if (nullptr == p) {     // 说明不够n个节点
            return head;
        }
        // 当链表节点够n个节点时,才进行真正的反转链表的操作。
        return trueReverseN(head, cnt);
    }

    ListNode *reverseKGropu(ListNode *head, int k) {
        if (nullptr == head || nullptr == head->next || 1 == k) {
            return head;
        }
        ListNode ret(0, head);  // 虚拟头节点
        ListNode *p = &ret;     // 初始时刻将指针p指向虚拟头节点,p节点的下一个节点即要进行反转部分链表的第一个节点
        ListNode *q = p->next;  // 初始时刻q指针指向要进行反转部分链表的第一个节点,反转后q指针指向反转部分链表的尾结点。
        
        // (p->next = reverseN(q, k)) != q:如果反转后返回的节点不为q节点,则说明反转成功。
        // 循环调用“递归法反转链表”
        while ((p->next = reverseN(q, k)) != q) {
            p = q;
            q = q->next;
        }
        return ret.next;
    }
};


int main() {
    ListNode *a = new ListNode(1);
    ListNode *b = new ListNode(2);
    ListNode *c = new ListNode(3);
    ListNode *d = new ListNode(4);
    ListNode *e = new ListNode(5);

    a->next = b;
    b->next = c;
    c->next = d;
    d->next = e;

    ListNode *head = a;
    printf("before reverse: ");
    while (head) {
        printf("%d ", head->val);
        head = head->next;
    }
    printf("\n");
    
    head = a;
    int k = 2;
    Solution *solution = new Solution();
    ListNode *ret = solution->reverseKGropu(head, 2);
    printf("after reverse: ");
    while (ret) {
        printf("%d ", ret->val);
        ret = ret->next;
    }
    
    return 0;
}
  • python代码
# -*- coding: utf-8 -*-

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def trueReverseN(self, head: ListNode, n: int) -> ListNode:
        if not head or not head.next or 1 == n:
            return head

        cur: ListNode = head.next
        pre: ListNode = self.trueReverseN(cur, n - 1)
        head.next = cur.next
        cur.next = head
        cur = cur.next
        return pre

    def reverseN(self, head: ListNode, num: int) -> ListNode:
        if not head or not head.next or 1 == num:
            return head

        cnt: int = num
        p: ListNode = head
        while num > 1 and p:
            p = p.next
            num -= 1

        if not p:
            return head

        return self.trueReverseN(head, cnt)


    def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        if not head or not head.next or 1 == k:
            return head

        ret = ListNode(0, head)
        p = ret
        q = p.next

        while True:
            p.next = self.reverseN(q, k)        # 注意是传入q节点,而不是head
            if p.next != q:
                p = q
                q = q.next
            else:
                break

        return ret.next


def main():
    a: ListNode = ListNode(1)
    b: ListNode = ListNode(2)
    c: ListNode = ListNode(3)
    d: ListNode = ListNode(4)
    e: ListNode = ListNode(5)

    a.next = b
    b.next = c
    c.next = d
    d.next = e

    head: ListNode = a

    print('before reverse: ', end='')
    while head:
        print(head.val, end=' ')
        head = head.next
    print()

    head = a
    solution = Solution()
    ret = solution.reverseKGroup(head, 2)

    print("after reverse: ", end='')
    while ret:
        print(ret.val, end=' ')
        ret = ret.next

if __name__ == "__main__":
    main()

说明

  • 对应LeetCode第25题。
  • 链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值