LeetCode 剑指 Offer 24. 反转链表(未更新完)

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

原题:反转链表
或直转:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/

本题自己的思路不是很通顺,以此在这里理清思路。

  • 自己的错误代码与思维路程
struct ListNode* count(struct ListNode* head,int* num,struct ListNode* result){
	if(head!=NULL&&*num==1){
		(*num)++;
    	count(head->next,num,result)->next=head;
    	head->next=NULL;
	}
	else if(head!=NULL&&*num!=1){
		(*num)++;
    	count(head->next,num,result)->next=head;
	}
	else if(head->next==NULL){
		result=head;
	}
	return head;
}

struct ListNode* reverseList(struct ListNode* head){
    int i;
    i=1;
    struct ListNode* myhead;
    count(head,&i,myhead);
    return myhead;
}

1、由于反转链表难以避免遍历的问题,理所应当想到递归和迭代
2、可是反转量表的每个结点指向在逻辑上又是相反的,即父亲变儿子,儿子变父亲
3、我就想到func(head->next)->next=head,即让头结点的指向结点的指针指向变为指向头结点,而不是指向下一个子节点
4、又由于func每调用一次都会运行这段代码,即func里面还有这段代码,因此需要迭代到head指向的next为NULL则停止。
5、由迭代的特性可知,虽然这段代码第一次作用的对象为根head,但由于迭代过程中在“->”符号前的函数就已经进入下一段func,即第一次运行func(xx)->next=head的代码为最后一段,即指向为NULL的。
6、程序也会按照这个逻辑从后向前推
7、下面遇到了一个问题,就是:

1->2->3->4->5->NULL
我们在利用这个方法的翻转后,原链表就变成了
1-><-2<-3<-4<-5
第一时间就会想到为什么不在第一次循环的时候就搞定它呢?结果是在递归过程中每个结点的next必不可少
第二时间会想到在递归结束后再进行指向,,我发现在循环中难以判断哪次是第一次,于是我新建了函数,引用了一个计数参数,试图利用计数功能在第一次时就改变指向,现在思考到错误了,不能咋第一次就修改指向,这样会影响迭代过程。

我决定再重新编辑一次代码,看我的。
。。。。。。
2021年3月25日21:14:32,我失败了

struct ListNode* myfunc(struct ListNode* head,int* num){
	if((head->next)!=NULL&&*(num)==1){
			*(num)++;
			myfunc(head->next,num)->next=head;
			head->next=NULL;		
		}
		else if((head->next)!=NULL&&*(num)!=1){
			*(num)++;
			myfunc(head->next,num)->next=head;
		}
		else if((head->next)==NULL){
			
		}
	return head;
}
struct ListNode* reverseList(struct ListNode* head){
	int a;
	a=1;
	int* num;
	num=&a;
	return myfunc(head,num);
}

原因是内存溢出,即编程不严谨,在访问空间的时候用到了不该用的内存,我吐了。下面咱们看一下题解所给,有和我思维差不多的,不过代码比我简洁多了。

  • 题解代码——遍历

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* prev = NULL;
    struct ListNode* curr = head;
    while (curr) {
        struct ListNode* next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
}

作者:LeetCode-Solution

根据阅读这段代码得到的信息,可知这是一个遍历的方法,让每一个指针的指向都指向其前一个node而不是后一个node。而每一次向下走的过程中我们发现,要是直接进行指向,则会丢失对下一个node的指向,于是我们需要新建立next指针来进行中转。即逻辑是这样的:
1、原来是从root开始,倒转之后从NULL开始,所以第一次的pre肯定是NULL,这里不直接用head,换用curr代替head,因为head指向不要变,让curr来实现遍历效果。
2、只要curr指向为非空,则表示当前还在链表的范围内,由于我们要实现链表中指针的调换,我们需要第三个指针变量才能进行置换,因此创建next指针。
3、让当前curr的next为前prev,这样就实现了将此结点的指针进行反向,可是我们也不能丢失下一个节点的前结点,因此prev就变成了curr,可见下一个prev永远是现在的curr。最后curr赋值为next,这个是刚开始就取到的next,最不能丢失的,通向接下来链表的钥匙。
4、遍历完成后整个链表ok的nono的就可以返回prev了,此时curr是NULL和next值一样。最后一次遍历中第一个prev是倒数第二个结点的指针,而第二个是当前结点的指针。
5、返回的就是当前最后一个结点的地址,也是逻辑上的翻转后的第一个

  • 题解代码——递归

“ 递归版本稍微复杂一些,其关键在于反向工作。假设链表的其余部分已经被反转,现在应该如何反转它前面的部分?”

是这样的,我也确实卡在了如何最后让第一个结点指向NULL,我利用了传数计数的形式,可是最后可能出现了数组越界,或者指针访问内存失败。。。。

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

作者:LeetCode-Solution

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值