【编程题】LeetCode.0025 K 个一组翻转链表

题目描述:
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

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

示例:
示例1:
在这里插入图片描述
示例2:
在这里插入图片描述

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

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

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

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

解析:
将一链表以每长度为k进行子链表的翻转,总步骤可概括为:

1.	分组,记得注意在最后一组链表的情况,不足k不需要翻转。
2.	对组内元素的翻转。
3.	拼接子链表。

先说一下对子链的翻转的方法:
方法一:迭代与递归
迭代代码:

ListNode* reverseList(ListNode* head) 
    {
        ListNode node,*ptr=&node,*temp;
        //当当前节点不为空节点时
        while (head)
        {
	        //先键一个指针存储当前节点
            temp = head;
            head = head->next;

            temp->next = ptr->next;
            ptr->next = temp;
        }
        return ptr->next;
    }

递归代码:

ListNode* reverseList(ListNode* head) 
    {
        if(head==nullptr||head->next==nullptr)
		{
            return head;
		}

        ListNode* new_node = reverseList(head->next);
        //关键:
        //以原先链表为基准,目前的链表结构是:
        //未翻转的链表部分-> head ->已经翻转的链表部分的末尾(这前半部分依旧保持原先顺序)<-已经翻转的链表的剩余部分
        //此刻,head节点与 原先链表的后继节点 形成环
        head->next->next = head;
        //断开环,使head成为翻转链表的末尾
        head->next = nullptr;

        return new_node;
    }

方法二:利用栈

ListNode* reverseList(ListNode* head) 
	{
		if(head==nullptr||head->next==nullptr)
		{
            return head;
		}

        ListNode dummyHead, * ptr = &dummyHead;
        stack<ListNode*> my_stack;

		while (head)
		{
            my_stack.push(head);
            head = head->next;
		}

		while (!my_stack.empty())
		{
            ListNode* temp = my_stack.top();
            my_stack.pop();

            ptr->next = temp;
            ptr = ptr->next;
		}
        //最后一定要记得把原链表的首节点后继指向nullptr,因为此刻它依然还是指向第二个元素
        ptr->next = nullptr;
        return dummyHead.next;
    }

其次是拼接问题,在子链翻转的过程中判断跳出循环的是否到达了空指针,因此我们这里也可以给函数多加一位参数,另设一个指针表示子链的末端。

代码:

class Solution {
public:
    pair<ListNode*,ListNode*> reverseList(ListNode *head,ListNode *end_node)
    {
        ListNode dummy_head, * ptr = &dummy_head;
        //原子链的首节点必为返回的尾节点
    	ListNode* return_end = head;
        //模拟子链末端的空指针
        ListNode* dummy_end = end_node->next;

        while (head != dummy_end)
        {
            ListNode* temp = head;
            head = head->next;

            temp->next = ptr->next;
            ptr->next = temp;
        }
        //返回的是翻转链表的首节点和末节点
        return { dummy_head.next,return_end };
    }
    ListNode* reverseKGroup(ListNode* head, int k) 
	{
        ListNode* dummy_head = new ListNode(0, head);
        //子链首节点的前序节点
        ListNode* start_node = dummy_head;

        while (head)
        {
	        //记录翻转前子链的末端
            ListNode* end_node = start_node;
            //计算子链长度
            for(int i=0;i<k;i++)
            {
                end_node = end_node->next;

                //长度不足K表示这是最后一段子链,则可以返回链表了
                if(!end_node)
                {
                    return dummy_head->next;
                }
            }

            //记录翻转子链的后继节点
            ListNode* next_node = end_node->next;

            pair<ListNode*, ListNode*> result = reverseList(head, end_node);
            head = result.first;
            end_node = result.second;
            //连接子链
            start_node->next = head;
            end_node->next = next_node;
            //更新节点
            start_node = end_node;
            head = start_node->next;
        }
        return dummy_head->next;
    }
};
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值