leetcode 206. Reverse Linked List(剑指offer16)、92. Reverse Linked List II

本文深入解析链表反转的两种常见算法,包括整个链表的反转和链表部分区间的反转。详细对比了不同实现方式的优缺点,特别是针对边界条件处理的差异,如链表只有一个节点的情况。通过具体代码示例,指出并纠正了容易引发运行时错误的编程陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

无论是1,还是2,删除链表都需要3个节点,只是现在这种最新写法只把cur作为了判断循环的依据,并且下一个节点的生成放在循环内。

 

206. Reverse Linked List

之前在牛客上的写法:

错误代码:

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if(pHead == NULL)
            return NULL;
        ListNode* p1 = pHead;
        ListNode* p2 = pHead->next;
        ListNode* p3 = pHead->next->next;
        pHead->next = NULL;
        while(p3 != NULL){
            p2->next = p1;
            p1 = p2;
            p2 = p3;
            p3 = p3->next;
        }
        p2->next = p1;
        return p2;
    }
};

此代码会报“段错误:您的程序发生段错误,可能是数组越界,堆栈溢出(比如,递归调用层数太多)等情况引起”

如果链表只有一个节点,那p2就是空指针,p3就是空指针的下一个指针,但空指针是没有next的

 

正确代码:

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if(pHead == NULL)
            return NULL;
        else if(pHead->next == NULL)
            return pHead;
        ListNode* p1 = pHead;
        ListNode* p2 = pHead->next;
        ListNode* p3 = pHead->next->next;
        pHead->next = NULL;
        while(p3 != NULL){
            p2->next = p1;
            p1 = p2;
            p2 = p3;
            p3 = p3->next;
        }
        p2->next = p1;
        return p2;
    }
};

 

个人觉得这种以当前节点为循环判断条件的方式比较好:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = NULL;
        while(head){
            ListNode* tmp = head->next;
            head->next = pre;
            pre = head;
            head = tmp;
        }
        return pre;
    }
};

 

 

 

92. Reverse Linked List II

依旧要在循环开始前获得pre和cur指针。

有个边界条件是m = 1的时候,可能第一个节点,即head指针也要反转,所以返回的时候返回head会出错。所以申请了一个指针,并且下一个节点就是head,这样无论哪种情况,都是申请指针的下一个节点。

注意pre的初始化也是在head之前,因为m <= 1实际上都是在head之前。还要注意m-1的设置,并且这个for循环就是找pre的位置。

i=m;i < n 比如3个节点的reverse,实际上只用操作2次就好了。

 

思路上:每次把cur的下一个节点旋转到cur之前去,pre节点实际上是不变的。

 

 

错误写法:

错误在tmp->next = cur;  第一次循环是对的,后面的就错了。cur指针是不变的,但是pre和cur之间的个数在增加,真正要放的位置是pre后面

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode* pre = new ListNode(-1),*res = pre;
        pre->next = head;
        res = pre;
        for(int i = 0;i < m - 1;i++)
            pre = pre->next;
        ListNode* cur = pre->next;
        for(int i = m;i < n;i++){
            ListNode* tmp = cur->next;
            cur->next = tmp->next;
            tmp->next = cur;
            pre->next = tmp;
        }
        return res->next;
    }
};

正确写法:

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode* pre = new ListNode(-1),*res = pre;
        pre->next = head;
        res = pre;
        for(int i = 0;i < m - 1;i++)
            pre = pre->next;
        ListNode* cur = pre->next;
        for(int i = m;i < n;i++){
            ListNode* tmp = cur->next;
            cur->next = tmp->next;
            tmp->next = pre->next;
            pre->next = tmp;
        }
        return res->next;
    }
};

 

转载于:https://www.cnblogs.com/ymjyqsx/p/10793483.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值