删去总和值为零的连续节点(前缀和)
题目描述
给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。删除完毕后,请你返回最终结果链表的头节点。
OJ链接 来源:力扣(LeetCode)
示例
解决
题目翻译
由于题目比较难理解,所以首先将题目用通俗易懂的语言描述一下:
将链表中和为的0 子链删除,直到不存在和为0的子链。
如下图所示,由于子链3 -3和为0,所以,我们应当知道被断开子链表的前驱节点 2,将其连接到被断开子链表的后继节点 5。
思路分析
通过计算前缀和,我们可以发现。红色部分和为3,橙色部分和为0,红色部分加上橙色部分后和还是为3,所以橙色部分就是要被删除的子链
如何删除呢?
将红色部分的最后一个节点(要删除子链的前驱节点)连接到橙色部分最后一个节点的下一个节点(要删除子链的后继节点)即可。
因此,我们可以一边遍历链表,一遍记录当前的和,如果之前存在这个和,那么就把他们中间的节点都断掉。
步骤
- 利用map集合保存当前遍历节点
cur
及其前缀和sum
- 如果map集合已经存在该前缀和,那么找到已存在的节点,让其连接到当前节点的下一节点,然后删除断开子链中各个节点的前缀和(更新map集合)
- 如果map集合中不存在,那么将其加入
代码实现
public ListNode removeZeroSumSublists(ListNode head)
{
HashMap<Integer, ListNode> map = new HashMap<>();
ListNode newHead = new ListNode(0, head);
map.put(0, newHead);
ListNode cur = head;
int sum = 0;
while (cur != null)
{
sum += cur.val;
if (map.containsKey(sum))
{
//1.删除子链
ListNode subListPrev = map.get(sum);//获取要删除子链的前驱节点
ListNode subListCur = subListPrev.next;//子链的遍历节点,初始值为子链的头节点
subListPrev.next = cur.next;//将子链的前驱节点连接到当前节点的下一节点
//2.更新map
int subListSum = sum;//保存当前和
while (subListCur != cur)//直到遍历到要删除子链的后继节点
{
subListSum += subListCur.val;
map.remove(subListSum);//移除map中保存的子链前缀和
subListCur = subListCur.next;
}
}
else
{
map.put(sum, cur);//添加当前节点及前缀和
}
cur = cur.next;//指针后移
}
return newHead.next;
}
}
cur = cur.next;//指针后移
}
return newHead.next;
}