Skip to content

Commit d936fc0

Browse files
committed
AlgoExpert Four Number Sum
1 parent 8cf4993 commit d936fc0

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,7 @@ First column links to the problem in AlgoExpert, second is the problem's difficu
10831083
| [Dijkstra's Algorithm][ae&dijkstra's-algorithm] | 🔴 Hard | [![python](res/py.png)][ae&dijkstra's-algorithm#py] |
10841084
| [First Duplicate Value][ae&first-duplicate-value] | 🟠 Medium | [![python](res/py.png)][ae&first-duplicate-value#py] |
10851085
| [First Non-Repeating Character][ae&first-non-repeating-character] | 🟢 Easy | [![python](res/py.png)][ae&first-non-repeating-character#py] |
1086+
| [Four Number Sum][ae&four-number-sum] | 🔴 Hard | [![python](res/py.png)][ae&four-number-sum#py] |
10861087
| [Generate Document][ae&generate-document] | 🟢 Easy | [![python](res/py.png)][ae&generate-document#py] |
10871088
| [Insertion Sort][ae&insertion-sort] | 🟢 Easy | [![python](res/py.png)][ae&insertion-sort#py] |
10881089
| [Kadane's Algorithm][ae&kadane's-algorithm] | 🟠 Medium | [![python](res/py.png)][ae&kadane's-algorithm#py] |
@@ -1130,6 +1131,8 @@ First column links to the problem in AlgoExpert, second is the problem's difficu
11301131
[ae&dijkstra's-algorithm#py]: algoexpert/dijkstras-algorithm.py
11311132
[ae&first-duplicate-value]: https://www.algoexpert.io/questions/first-duplicate-value
11321133
[ae&first-duplicate-value#py]: algoexpert/first-duplicate-value.py
1134+
[ae&four-number-sum]: https://www.algoexpert.io/questions/four-number-sum
1135+
[ae&four-number-sum#py]: algoexpert/four-number-sum.py
11331136
[ae&first-non-repeating-character]: https://www.algoexpert.io/questions/first-non-repeating-character
11341137
[ae&first-non-repeating-character#py]: algoexpert/first-non-repeating-character.py
11351138
[ae&generate-document]: https://www.algoexpert.io/questions/generate-document

algoexpert/four-number-sum.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Four Number Sum
2+
# 🔴 Hard
3+
#
4+
# https://www.algoexpert.io/questions/four-number-sum
5+
#
6+
# Tags: Array - Sorting
7+
8+
import timeit
9+
from collections import defaultdict
10+
11+
12+
# The brute force solution explores all options using nested loops.
13+
#
14+
# Time complexity: O(n^4) - Four levels deep nested loops.
15+
# Space complexity: O(1) - Constant space is used.
16+
class BruteForce:
17+
def fourNumberSum(self, array, targetSum):
18+
res = []
19+
for i in range(len(array) - 3):
20+
for j in range(i + 1, len(array) - 2):
21+
for k in range(j + 1, len(array) - 1):
22+
for m in range(k + 1, len(array)):
23+
vals = [array[i], array[j], array[k], array[m]]
24+
if sum(vals) == targetSum:
25+
res.append(vals)
26+
return res
27+
28+
29+
# Use a hashmap of pair sums to find target quadruplets in O(n^2) time.
30+
#
31+
# Time complexity: O(n^2) - Nested loops with constant time operations
32+
# in the inner loop.
33+
# Space complexity: O(n^2) - The hashmap will hold the sum of all pairs.
34+
class Solution:
35+
def fourNumberSum(self, array, targetSum):
36+
# Use a hashmap of pair sums to the pairs that add up to them.
37+
# Use a set to store quadruplets to eliminate duplicates. The OJ
38+
# accepts a set of tuples as the result.
39+
sums, res = defaultdict(set), set()
40+
# Iterate over all pairs in O(n^2).
41+
for i in range(len(array) - 1):
42+
for j in range(i + 1, len(array)):
43+
vals = (array[i], array[j])
44+
s = array[i] + array[j]
45+
if targetSum - s in sums:
46+
for pair in sums[targetSum - s]:
47+
if array[i] not in pair and array[j] not in pair:
48+
res.add(
49+
tuple(
50+
sorted(
51+
[pair[0], pair[1], array[i], array[j]]
52+
)
53+
)
54+
)
55+
sums[s].add(vals)
56+
return res
57+
58+
59+
def test():
60+
executors = [
61+
BruteForce,
62+
Solution,
63+
]
64+
tests = [
65+
[[1, 2, 3, 4, 5, 6, 7], 10, [[1, 2, 3, 4]]],
66+
[[7, 6, 4, -1, 1, 2], 16, [[7, 6, 4, -1], [7, 6, 1, 2]]],
67+
[
68+
[5, -5, -2, 2, 3, -3],
69+
0,
70+
[[-5, -3, 3, 5], [-5, -2, 2, 5], [-3, -2, 2, 3]],
71+
],
72+
]
73+
for executor in executors:
74+
start = timeit.default_timer()
75+
for _ in range(1):
76+
for col, t in enumerate(tests):
77+
sol = executor()
78+
result = sol.fourNumberSum(t[0], t[1])
79+
# The result could be in any order.
80+
result = sorted(map(sorted, result))
81+
exp = sorted(map(sorted, t[2]))
82+
assert result == exp, (
83+
f"\033[93m» {result} <> {exp}\033[91m for"
84+
+ f" test {col} using \033[1m{executor.__name__}"
85+
)
86+
stop = timeit.default_timer()
87+
used = str(round(stop - start, 5))
88+
cols = "{0:20}{1:10}{2:10}"
89+
res = cols.format(executor.__name__, used, "seconds")
90+
print(f"\033[92m» {res}\033[0m")
91+
92+
93+
test()

0 commit comments

Comments
 (0)