LeetCode206: 反转链表

描述

 给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

数据范围: 0≤n≤1000

要求:空间复杂度 O(1)O(1) ,时间复杂度 O(n)O(n) 。

如当输入链表{1,2,3}时,

经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。

以上转换过程如下图所示:

题解

注意:本题代码全为不带头结点的链表逆置,若带头结点,则需要先将头节点的next指向空,逆置后再链接即可。(迭代法和头插法)

 迭代法求解(原地逆置)

struct ListNode
{
	int val;
	struct ListNode *next;
};

class Solution {
public:
    ListNode* reverseList(ListNode* head)
    {
        ListNode* curr = head;
        ListNode* next;
        ListNode* prior = NULL;

        while(curr!=NULL)
        {
            next = curr->next;//保存当前结点的下一个结点
            curr->next = prior;//将当前结点的next指向它前一个结点(初始为空)
            prior = curr;//更新前一个结点为当前节点
            curr = next;//curr = curr->next;//更新当前节点为下一个结点
        }
        return prior;
    }
};

递归法求解

class Solution {
public:
    ListNode* reverseList(ListNode* head)
    {
        //若链表本身为空或找到了链表最后一个结点,则直接返回head结点
        if(head==NULL||head->next==NULL)
            return head; 
        //递归翻转
        ListNode* newhead =  reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return newhead;
    }
};

头插法求解 

与迭代法本质相同,只不过头插法是新建一个链表,对其在头部插入原链表的结点。

(注:如果该链表本身自带头节点,则可以将头节点的next置为NULL,然后就在该头节点之后进行头插法插入结点,相当于用头插法在带头结点的链表中原地逆置!)

class Solution {
public:
    ListNode* reverseList(ListNode* head) 
    {
        ListNode* pHead = new ListNode(0);//新链表,设置一个哑节点作为头节点,避免特殊处理
        ListNode* curr = head;
        //遍历旧链表
        while(curr)
        {
            ListNode* next = curr->next;//保存下一节点
            curr->next = pHead->next;
            pHead->next = curr;
            curr = next;
        }
        return pHead->next;
    }
};

进阶:每k个一组反转链表

迭代法(头插法)

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) 
    {
        ListNode* dummy = new ListNode(0,head);
        ListNode* curr = head;
        int len = 0;//先计算出链表的长度
        while(curr != NULL) {
            len++;
            curr = curr->next;
        }
        int n = len/k;//计算出有几组
        ListNode* pre = dummy;
        curr = head;
        for(int i=0;i<n;i++) 
        {
            for(int j=0;j<k-1;j++) 
            {
                //原地头插法逆置:pre为头,插到pre之后,其他节点之前
                ListNode* t = curr->next;//保存下一结点
                curr->next = t->next;
                t->next = pre->next;//注意该地方的pre->next不可以为curr!因为curr并不是总等于pre->next
                pre->next = t;
            }
            pre = curr;//更新新的头
            curr = curr->next;
        }
        return dummy->next;
    }
};

总结

任何关于链表的逆置问题,就考虑四个步骤:

1.首先把下一节点保存下来 next = curr->next;

2.curr->next该指向哪里 curr->next = A;

3.A该指向哪里 A  = B

4.B该指向哪里(这一步其实就是更新当前结点)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dorakmon0219

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值