从链表中删去总和值为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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

©️2020 CSDN 皮肤主题: 1024 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值