1171-从链表中删去总和值为零的连续节点

Raphael Liu Lv10

给你一个链表的头节点 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]

提示:

  • 给你的链表中可能有 11000 个节点。
  • 对于链表中的每个节点,节点的值:-1000 <= node.val <= 1000.

方法一:哈希表

给你一个链表的头节点 head,反复删去链表中总和值为 0 的连续节点组成的序列。

建立一个 dummy 节点,指向 head,节点值为 0。遍历一遍链表,同时记录前缀和,以当前前缀和为 key,当前节点为 value,存入哈希表中。如果相同前缀和已经存在,就可以直接覆盖掉原有节点。

第二遍重新遍历链表,同时记录前缀和 prefix,哈希表中对应 prefix 的节点是最后一次出现相同前缀和的节点,我们将这个节点的下一个节点,赋值给当前节点的下一个节点,中间跳过的部分总和即为 0。

最后我们返回 dummy 节点的下一节点,作为新的头节点。注意满足题目要求的答案不唯一,可以返回任何满足题目要求的答案。

[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
ListNode* removeZeroSumSublists(ListNode* head) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
int prefix = 0;
unordered_map<int, ListNode*> seen;
for (ListNode* node = dummy; node; node = node->next) {
prefix += node->val;
seen[prefix] = node;
}
prefix = 0;
for (ListNode* node = dummy; node; node = node->next) {
prefix += node->val;
node->next = seen[prefix]->next;
}
return dummy->next;
}
};
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public ListNode removeZeroSumSublists(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
Map<Integer, ListNode> seen = new HashMap<>();
int prefix = 0;
for (ListNode node = dummy; node != null; node = node.next) {
prefix += node.val;
seen.put(prefix, node);
}
prefix = 0;
for (ListNode node = dummy; node != null; node = node.next) {
prefix += node.val;
node.next = seen.get(prefix).next;
}
return dummy.next;
}
}
[sol1-C#]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Solution {
public ListNode RemoveZeroSumSublists(ListNode head) {
int prefix = 0;
ListNode dummy = new ListNode(0);
dummy.next = head;
Dictionary<int, ListNode> seen = new Dictionary<int, ListNode>();
seen[0] = dummy;
for (ListNode node = dummy; node != null; node = node.next) {
prefix += node.val;
seen[prefix] = node;
}
prefix = 0;
for (ListNode node = dummy; node != null; node = node.next) {
prefix += node.val;
node.next = seen[prefix].next;
}
return dummy.next;
}
}
[sol1-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
def removeZeroSumSublists(self, head: Optional[ListNode]) -> Optional[ListNode]:
prefix = 0
seen = {}
seen[0] = dummy = ListNode(0)
dummy.next = head
while head:
prefix += head.val
seen[prefix] = head
head = head.next
head = dummy
prefix = 0
while head:
prefix += head.val
head.next = seen[prefix].next
head = head.next
return dummy.next
[sol1-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var removeZeroSumSublists = function(head) {
let dummy = new ListNode(0);
dummy.next = head;
let seen = {};
let prefix = 0;
for (let node = dummy; node !== null; node = node.next) {
prefix += node.val;
seen[prefix] = node;
}
prefix = 0;
for (let node = dummy; node !== null; node = node.next) {
prefix += node.val;
node.next = seen[prefix].next;
}
return dummy.next;
};
[sol1-Go]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func removeZeroSumSublists(head *ListNode) *ListNode {
dummy := &ListNode{Val: 0}
dummy.Next = head
seen := map[int]*ListNode{}
prefix := 0
for node := dummy; node != nil; node = node.Next {
prefix += node.Val
seen[prefix] = node
}
prefix = 0
for node := dummy; node != nil; node = node.Next {
prefix += node.Val
node.Next = seen[prefix].Next
}
return dummy.Next
}
[sol1-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
typedef struct {
int key;
struct ListNode *val;
UT_hash_handle hh;
} HashItem;

HashItem *hashFindItem(HashItem **obj, int key) {
HashItem *pEntry = NULL;
HASH_FIND_INT(*obj, &key, pEntry);
return pEntry;
}

bool hashAddItem(HashItem **obj, int key, const struct ListNode* val) {
if (hashFindItem(obj, key)) {
return false;
}
HashItem *pEntry = (HashItem *)malloc(sizeof(HashItem));
pEntry->key = key;
pEntry->val = val;
HASH_ADD_INT(*obj, key, pEntry);
return true;
}

bool hashSetItem(HashItem **obj, int key, const struct ListNode* val) {
HashItem *pEntry = hashFindItem(obj, key);
if (!pEntry) {
hashAddItem(obj, key, val);
} else {
pEntry->val = val;
}
return true;
}

struct ListNode * hashGetItem(HashItem **obj, int key) {
HashItem *pEntry = hashFindItem(obj, key);
if (!pEntry) {
return NULL;
}
return pEntry->val;
}

void hashFree(HashItem **obj) {
HashItem *curr = NULL, *tmp = NULL;
HASH_ITER(hh, *obj, curr, tmp) {
HASH_DEL(*obj, curr);
free(curr);
}
}

struct ListNode* createListNode(int val) {
struct ListNode *obj = (struct ListNode *)malloc(sizeof(struct ListNode));
obj->val = val;
obj->next = NULL;
return obj;
}

struct ListNode* removeZeroSumSublists(struct ListNode* head) {
struct ListNode* dummy = createListNode(0);
dummy->next = head;
int prefix = 0;
HashItem *seen = NULL;
for (struct ListNode* node = dummy; node; node = node->next) {
prefix += node->val;
hashSetItem(&seen, prefix, node);
}
prefix = 0;
for (struct ListNode* node = dummy; node; node = node->next) {
prefix += node->val;
struct ListNode *curr = hashGetItem(&seen, prefix);
if (curr) {
node->next = curr->next;
}
}
hashFree(&seen);
struct ListNode* ret = dummy->next;
free(dummy);
return ret;
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。

  • 空间复杂度:O(n),其中 n 是链表的长度。

 Comments
On this page
1171-从链表中删去总和值为零的连续节点