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