# 从链表中删去总和值为零的连续节点
给你一个链表的头节点 head
,请你编写代码,反复删去链表中由 总和值为 0
的连续节点组成的序列,直到不存在这样的序列为止。
删除完毕后,请你返回最终结果链表的头节点。
输入:head = [1,2,-3,3,1] 输出:[3,1] 提示:答案 [1,2,1] 也是正确的。
>
输入:head = [1,2,3,-3,4] 输出:[1,2,4]
这题难就难在我们操作的对象是个链表,如果是数组的话,一下就变得特别简单了,从第一个数开始出发,遇到 0 可以直接删除,或者总和为 0 的时候,也可以把之前累加的都删除掉。如果一直加到最后都没有和为 0 的结果,那么就从第二个出发,以此类推,直到遍历到最后一个数。
关键是现在换成了链表,不过想一下,还是可以把一个链表变成像数组那样操作,那么自然而然就可以联系到用哈希表来解决这个问题。
首先,先遍历链表建立哈希,得到一个类数组对象,接着开始遍历这个类数组对象,求和,如果遇到和为 0 了,就把之前的节点全部丢弃,对剩余的节点递归进行上述操作。
算法实现如下:
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var removeZeroSumSublists = function (head) {
if (!head) {
return null;
}
let newHead = head;
let preNode = null;
// 根据链表生成映射
const posMap = makeHash(head);
for (let i = 0; posMap[i]; i++) {
let currentNode = posMap[i];
let node = currentNode;
let sum = 0;
// 对从当前节点开始到最后一个节点求和,若为0,则丢弃这期间的所有节点,并且递归的进行删除操作
while (node) {
sum += node.val;
if (sum == 0) {
if (preNode === null) {
head = node.next;
} else {
preNode.next = node.next;
}
return removeZeroSumSublists(head);
} else {
node = node.next;
}
}
// 没有和为0的连续节点,将当前节点保留下来
preNode = currentNode;
}
return newHead;
};
/**
* 将链表生成类数组对象
* @param {ListNode} head
* @returns
*/
var makeHash = function (head) {
let node = head;
let map = Object.create(null);
let counter = 0;
while (node) {
map[counter] = node;
node = node.next;
counter++;
}
map.length = counter;
return map;
};