力扣206. 反转链表 多解&个人踩的坑

解法一 迭代

最直接的想法,利用链表特性
使用beg,mid,end三个指针,在向后访问过程中将原链表中指针逆向
例如 1 → 2 1\rightarrow2 12 转为 1 ← 2 1\leftarrow2 12

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr)
        	return head;
    	else if(head->next == nullptr)
    		return head;                              //只有一个或无节点直接返回
    	ListNode *beg = head,*mid = beg->next,*end = nullptr;
    	head->next = nullptr;                         //原头指针倒置后应当指向null
    	while(mid){
    		end = mid->next;                         //逆向前保存“高位”信息 
    		mid->next = beg;                         //逆向
    		beg = mid;                               //迭代向前
    		mid = end;
		}
		return beg;
    }
};

踩的坑

  • 未利用链式存储特性,只想采用顺序表插入方式
  • 未设置原头指针next为null,导致力扣出现执行出错情况(这也很好理解,head->next==null 为链表顺序遍历至末尾标志)

执行出错:堆在释放后使用(heap-use-after-free),一般和随意释放内存有关。

但是我并没有动态分配内存
未设置原头指针next为null,第一个元素仍然指向第二个元素,因而导致第一二个元素间形成了一个环,可能会倒置判题内部程序出现这样的问题吧?

执行出错报错大概就像这样:
在这里插入图片描述

另一实现

将beg,mid,end向前提,在一开始就完成设置原头指针next为null
不需在循环外设置head->next = nullptr

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr)
        	return head;
    	else if(head->next == nullptr)
    		return head;
    	ListNode *beg = nullptr,*mid = head,*high = nullptr;
    	while(mid){
    		high = mid->next;
    		mid->next = beg;
    		beg = mid;
    		mid = high;
		}
		return beg;
    }
};

解法二 重新插入

类似尾插法

断开头指针,依次重新插入,将head当作尾指针依次向后移

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr)
        	return head;
    	else if(head->next == nullptr)
    		return head;
    	ListNode* p = head;
		head = nullptr;                             //断开头结点
		while(p){
			ListNode* NextNode = p->next;           //后续更改p,提前保存下一个结点信息
			p->next = head;
			head = p;
			p = NextNode;
		}
		return head;
    }
};

踩的坑

  • 链表无头结点,头指针直接指向首元结点(头结点显然不是必须的,本题就没有)
  • 变量更新的顺序,例如在p改变前保存NextNode

头插法

在新链表中增加头结点(原链表无头结点),在头结点和首元结点之间不断插入(后插入的元素离头结点近),完成倒序

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr)
        	return head;
    	else if(head->next == nullptr)
    		return head;
    	ListNode* p = new ListNode;                          //p作为新链表头结点
        p->next = nullptr;                                   //初始时头结点指向null
        while(head){                                         //head向后遍历原链表
    	    ListNode* NextNode = head->next;                
            head->next = p->next;                            //头插法
            p->next = head;      
            head = NextNode;
        }
        return p->next;
    }
};

踩的坑

  • 新链表头结点p需要动态分配内存,不然会报错:member access within address 0x602000000058 with insufficient space for an object of type ‘ListNode’ (solution.cpp) 即结点p空间不足

解法三 递归

想不到
递归访问至尾结点,并将其设为p(倒置后头结点)后向上返回
先看最简单的倒数第二个结点情况:
作为函数参数传入的不是头指针,就是倒数第二个结点。通过head->next->next = head完成倒置,并设next为null(很关键,通过递归不断设置为最后一个节点)
再向上返回函数至倒数第三个结点。注意:原链表结构并未完全改变,倒数第三个节点仍然指向倒二结点,因此可以重复上述倒置过程
递归调用,完成倒置
在这里插入图片描述

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr)
        	return head;
    	else if(head->next == nullptr)
    		return head;
    	ListNode *p = reverseList(head->next);            //previous tail node 
    	head->next->next = head;
    	head->next = nullptr; 
		return p;
    }
};

踩的坑

  • 头尾结点倒置后已经互换,应该直接返回p,而不是head
  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值