diff --git a/18. 4Sum/18. 4Sum.csproj b/18. 4Sum/18. 4Sum.csproj
new file mode 100644
index 0000000..23f8dba
--- /dev/null
+++ b/18. 4Sum/18. 4Sum.csproj
@@ -0,0 +1,11 @@
+
+
+
+ Exe
+ net10.0
+ _18._4Sum
+ enable
+ enable
+
+
+
diff --git a/18. 4Sum/Program.cs b/18. 4Sum/Program.cs
new file mode 100644
index 0000000..fe6e509
--- /dev/null
+++ b/18. 4Sum/Program.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+var sol = new Solution();
+
+var cases = new (int[] nums, int target, int[][] expected)[]
+{
+ // (new[] { 1, 0, -1, 0, -2, 2 }, 0, new[]
+ // {
+ // new[] { -2, -1, 1, 2 },
+ // new[] { -2, 0, 0, 2 },
+ // new[] { -1, 0, 0, 1 }
+ // }),
+ // (new[] { 2, 2, 2, 2, 2 }, 8, new[]
+ // {
+ // new[] { 2, 2, 2, 2 }
+ // }),
+ // (new[] { -3, -1, 0, 2, 4, 5 }, 2, new[]
+ // {
+ // new[] { -3, -1, 2, 4 }
+ // }),
+ (new[] { 1000000000, 1000000000, 1000000000, 1000000000 }, -294967296, Array.Empty())
+};
+
+foreach (var (nums, target, expected) in cases)
+{
+ var actual = sol.FourSum(nums, target);
+ Console.WriteLine($"nums={FormatArray(nums)}, target={target} -> {FormatResults(actual)} (expected: {FormatResults(expected)})");
+}
+
+static string FormatArray(int[] nums)
+{
+ return $"[{string.Join(",", nums)}]";
+}
+
+static string FormatResults(IList> results)
+{
+ return "[" + string.Join(",", results.Select(r => $"[{string.Join(",", r)}]")) + "]";
+}
diff --git a/18. 4Sum/Solution.cs b/18. 4Sum/Solution.cs
new file mode 100644
index 0000000..7b1904c
--- /dev/null
+++ b/18. 4Sum/Solution.cs
@@ -0,0 +1,143 @@
+
+public class Solution
+{
+ record struct TwoSumSource(int A, int B)
+ {
+ public override string ToString()
+ {
+ return $"({A}+{B}={A + B})";
+ }
+ }
+
+ record struct AnswerRow(int? N0 = null, int? N1 = null, int? N2 = null, int? N3 = null)
+ {
+
+ public void PushNum(int num)
+ {
+ if (N0 == null)
+ {
+ N0 = num;
+ }
+ else if (N1 == null)
+ {
+ N1 = num;
+ if (N0 > N1)
+ {
+ (N0, N1) = (N1, N0);
+ }
+ }
+ else if (N2 == null)
+ {
+ N2 = num;
+ if (N1 > N2)
+ {
+ (N1, N2) = (N2, N1);
+ }
+ if (N0 > N1)
+ {
+ (N0, N1) = (N1, N0);
+ }
+ }
+ else if (N3 == null)
+ {
+ N3 = num;
+ if (N2 > N3)
+ {
+ (N2, N3) = (N3, N2);
+ }
+ if (N1 > N2)
+ {
+ (N1, N2) = (N2, N1);
+ }
+ if (N0 > N1)
+ {
+ (N0, N1) = (N1, N0);
+ }
+ }
+ else if (num < N3)
+ {
+ N3 = num;
+ if (N2 > N3)
+ {
+ (N2, N3) = (N3, N2);
+ }
+ if (N1 > N2)
+ {
+ (N1, N2) = (N2, N1);
+ }
+ if (N0 > N1)
+ {
+ (N0, N1) = (N1, N0);
+ }
+ }
+ }
+ }
+
+
+ public IList> FourSum(int[] nums, int target)
+ {
+ var dict = new Dictionary();
+ // суммы из двух слагаемых, все возможные
+ var twoSums = new Dictionary>();
+ for (var i = 0; i < nums.Length; i++)
+ {
+ var num1 = nums[i];
+ dict.TryAdd(num1, 0);
+ dict[num1]++;
+ for (var j = i + 1; j < nums.Length; j++)
+ {
+ var num2 = nums[j];
+ var sum = num1 + num2;
+ twoSums.TryAdd(sum, new HashSet());
+ twoSums[sum].Add(new TwoSumSource() { A = num1, B = num2 });
+ }
+ }
+
+ var rows = new HashSet();
+ // словарь для требуемоего количества чисел
+ var needDict = new Dictionary();
+ foreach (var kp1 in dict)
+ {
+ var needThreeSum = target - kp1.Key;
+ needDict.TryAdd(kp1.Key, 0);
+ needDict[kp1.Key]++;
+ foreach (var kp2 in dict)
+ {
+ needDict.TryAdd(kp2.Key, 0);
+ needDict[kp2.Key]++;
+
+ var needTwoSum = (long)needThreeSum - kp2.Key;
+ if (twoSums.TryGetValue(needTwoSum, out var curTwoSums))
+ {
+ foreach (var curTwoSum in curTwoSums)
+ {
+ needDict.TryAdd(curTwoSum.A, 0);
+ needDict[curTwoSum.A]++;
+
+ needDict.TryAdd(curTwoSum.B, 0);
+ needDict[curTwoSum.B]++;
+
+ if (needDict.All(kp => dict[kp.Key] >= kp.Value))
+ {
+ var row = new AnswerRow();
+ row.PushNum(kp1.Key);
+ row.PushNum(kp2.Key);
+ row.PushNum(curTwoSum.A);
+ row.PushNum(curTwoSum.B);
+ rows.Add(row);
+ }
+
+ needDict[curTwoSum.A]--;
+ needDict[curTwoSum.B]--;
+ }
+ }
+ needDict[kp2.Key]--;
+ }
+ needDict.Clear();
+ }
+ var answer = new List>(rows.Count);
+ foreach (var row in rows)
+ answer.Add(new List { row.N0!.Value, row.N1!.Value, row.N2!.Value, row.N3!.Value });
+ return answer;
+ }
+}
\ No newline at end of file
diff --git a/Leetcode.sln b/Leetcode.sln
index 6feaf32..83f6d2b 100644
--- a/Leetcode.sln
+++ b/Leetcode.sln
@@ -183,6 +183,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "2906. Construct Product Mat
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "3546. Equal Sum Grid Partition I", "3546. Equal Sum Grid Partition I\3546. Equal Sum Grid Partition I.csproj", "{8533B947-4274-46C9-8EEA-1439778FEE32}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "18. 4Sum", "18. 4Sum\18. 4Sum.csproj", "{0AF9E85C-7CCC-4E82-80B6-39931EA17D52}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1273,6 +1275,18 @@ Global
{8533B947-4274-46C9-8EEA-1439778FEE32}.Release|x64.Build.0 = Release|Any CPU
{8533B947-4274-46C9-8EEA-1439778FEE32}.Release|x86.ActiveCfg = Release|Any CPU
{8533B947-4274-46C9-8EEA-1439778FEE32}.Release|x86.Build.0 = Release|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Debug|x64.Build.0 = Debug|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Debug|x86.Build.0 = Debug|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Release|x64.ActiveCfg = Release|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Release|x64.Build.0 = Release|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Release|x86.ActiveCfg = Release|Any CPU
+ {0AF9E85C-7CCC-4E82-80B6-39931EA17D52}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE