给你一个链表的头节点 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
递归
- 先考虑最小情况,
head=NULL
时返回NULL
- 缩小规模,直到
head = NULL
,那链表向后走就可以了
struct ListNode* removeZeroSumSublists(struct ListNode* head)
{
if(!head)
return NULL;
struct ListNode* p = removeZeroSumSublists(head->next);
...
}
我们来看,这样下去会走到哪一步。
- 归
缩小一直调用函数直到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;
}
当然这一题递归用的时间其实是更长的。
递归记得几点
- 最小情况最先写
- 递到最小情况
- 归来时考虑最后一种情况怎么写(尾递归不用写)
- 考虑要返回谁?想想最后一个归怎么返回才对。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-zero-sum-consecutive-nodes-from-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。