从链表中删去总和值为0的连续结点

给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。删除完毕后,请你返回最终结果链表的头节点。

你可以返回任何满足题目要求的答案。(注意,下面示例中的所有序列,都是对 ListNode 对象序列化的表示。)

示例 1:
输入:head = [1,2,-3,3,1]
输出:[3,1]
提示:答案 [1,2,1] 也是正确的。

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

示例 3:
输入:head = [1,2,3,-3,-2]
输出:[1]

方法1

两次循环

struct ListNode* removeZeroSumSublists(struct ListNode* head)
{
    struct ListNode* p = (struct ListNode*)malloc(sizeof(struct ListNode));
    p->next = head;
    p->val = 0;
    struct ListNode* record1 = NULL;
    struct ListNode* record2 = p;
    int sum = 0;
    while (record2)
    {
        sum = 0;
        record1 = record2->next;//第一次就是head
        while (record1)
        {
            sum += record1->val;
            if (sum == 0)
            {
                record2->next = record1->next;//record2开始到record1的位置和为0
            }
            record1 = record1->next;
        }
        record2 = record2->next;
    }
    return p->next;
}

方法2

递归

  1. 先考虑最小情况,head=NULL时返回NULL
  2. 缩小规模,直到head = NULL,那链表向后走就可以了
struct ListNode* removeZeroSumSublists(struct ListNode* head)
{
    if(!head)
        return NULL;
    struct ListNode* p = removeZeroSumSublists(head->next);	
    ...
}

我们来看,这样下去会走到哪一步。
在这里插入图片描述


  1. 缩小一直调用函数直到head=NULL才会有返回值NULL进而走向下一步。p = NULL此时head->val是5。每次返回head,也就相当于从后向前进,这就是递归的了。那这样可以从,5 ,然后3,5,然后-3,3,5都看成是一个链表,再去比较。.

观察一下怎么走的

在这里插入图片描述
可以把这种情况(-3 3)当成是规模变大()的最后一种情况,因为所有情况都可以这样做,所以找到这种怎么做就可以,这就是上面的...怎么写。
那么这个函数肯定有返回,那head必然前移,所有只有下面这样做才能满足条件。

	head->next = p;
//要保证head接到每次返回的p,但其实除了要删时此句有用,其余都无用,因为head->next会返回head
	struct ListNode* temp = head;
	int value = 0;
	while(temp)//把每一个temp都作为一个链表
	{
	    value += temp->val;
	    if(0 == value)
	        return temp->next;//给了p
	    temp = temp->next;
	}

在这里插入图片描述
temp = 3时返回一个temp->next就是5那个结点给了p,但是head只会再向前走,因为它只会归了,不管你怎么走,它怎么来的就怎么回去,而下一步head->next = p就去掉了两个结点。

struct ListNode* removeZeroSumSublists(struct ListNode* head)
{
/*           1               */
    if(!head)
    	return NULL;
/*           2               */   	
    struct ListNode* p = removeZeroSumSublists(head->next);	
/*           3              */	    
	head->next = p;
	struct ListNode* temp = head;
	int value = 0;
	while(temp)//把每一个temp都作为一个链表
	{
	    value += temp->val;
	    if(0 == value)
	        return temp->next;
	    temp = temp->next;
	}
	...
}

那这最后一个...应该返回什么呢?
因为要的是链表的头,而head一直在,这与逆转链表不同,以应该返回head

struct ListNode* removeZeroSumSublists(struct ListNode* head)
{
/*           1               */
    if(!head)
    	return NULL;
/*           2               */   	
    struct ListNode* p = removeZeroSumSublists(head->next);	
/*           3              */	    
	head->next = p;
	struct ListNode* temp = head;
	int value = 0;
	while(temp)//把每一个temp都作为一个链表
	{
	    value += temp->val;
	    if(0 == value)
	        return temp->next;
	    temp = temp->next;
	}
/*           4              */		
	return head;
}

当然这一题递归用的时间其实是更长的。

递归记得几点

  1. 最小情况最先写
  2. 递到最小情况
  3. 归来时考虑最后一种情况怎么写(尾递归不用写)
  4. 考虑要返回谁?想想最后一个怎么返回才对。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-zero-sum-consecutive-nodes-from-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个可能的C语言实现: ```c #include <stdio.h> #include <stdlib.h> // 定义链表结点 struct Node { int val; struct Node* next; }; // 找到链表值最小的结点删除它 void deleteMinNode(struct Node** head) { if (*head == NULL) { // 空链表 return; } // 找到值最小的结点 struct Node* minNode = *head; struct Node* prev = NULL; struct Node* curr = *head; while (curr != NULL) { if (curr->val < minNode->val) { minNode = curr; prev = prev; } prev = curr; curr = curr->next; } // 删除最小结点 if (minNode == *head) { *head = (*head)->next; } else { prev->next = minNode->next; } free(minNode); } int main() { // 创建一个链表 struct Node* head = NULL; head = (struct Node*)malloc(sizeof(struct Node)); head->val = 5; head->next = (struct Node*)malloc(sizeof(struct Node)); head->next->val = 3; head->next->next = (struct Node*)malloc(sizeof(struct Node)); head->next->next->val = 8; head->next->next->next = NULL; // 删除值最小的结点 deleteMinNode(&head); // 打印链表 struct Node* curr = head; while (curr != NULL) { printf("%d ", curr->val); curr = curr->next; } printf("\n"); // 释放链表内存 curr = head; while (curr != NULL) { struct Node* temp = curr; curr = curr->next; free(temp); } return 0; } ``` 这个程序首先定义了链表结点的结构体 `Node`,然后实现了一个函数 `deleteMinNode`,它的参数是指向指针的指针 `head`,即指向链表头指针的指针。该函数会在链表找到值最小的结点删除它,最后释放它的内存。注意,因为要修改指针 `head` 的值,所以要传入指向 `head` 的指针的指针。 在 `main` 函数,我们创建了一个简单的链表,并调用了 `deleteMinNode` 函数来删除值最小的结点。最后,我们打印链表以验证删除操作是否正确,并释放链表内存。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CCPigSnail

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

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

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

打赏作者

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

抵扣说明:

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

余额充值