From 37f2fea0d03b224d36bb8efcdd9dad87005b9ae2 Mon Sep 17 00:00:00 2001 From: javy99 Date: Tue, 10 Jun 2025 21:30:14 +0200 Subject: [PATCH] add solution for 3 sum problem --- 2_two_pointers/3_3sum/solution.go | 105 +++++++++++++++++++++++++ 2_two_pointers/3_3sum/solution_test.go | 67 ++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 2_two_pointers/3_3sum/solution.go create mode 100644 2_two_pointers/3_3sum/solution_test.go diff --git a/2_two_pointers/3_3sum/solution.go b/2_two_pointers/3_3sum/solution.go new file mode 100644 index 0000000..fe274fb --- /dev/null +++ b/2_two_pointers/3_3sum/solution.go @@ -0,0 +1,105 @@ +package sum + +import ( + "sort" +) + +// Time complexity: O(n^3) +// Space complexity: O(n) +func ThreeSumBruteForce(nums []int) [][]int { + n := len(nums) + result := map[[3]int]bool{} + + for i := 0; i < n; i++ { + for j := i + 1; j < n; j++ { + for k := j + 1; k < n; k++ { + if nums[i]+nums[j]+nums[k] == 0 { + triplet := []int{nums[i], nums[j], nums[k]} + sort.Ints(triplet) // to avoid duplicate triplets in different orders + var key [3]int + copy(key[:], triplet) + result[key] = true + } + } + } + } + + // convert map to slice - initialize empty slice to avoid nil + output := make([][]int, 0) + for k := range result { + output = append(output, []int{k[0], k[1], k[2]}) + } + return output +} + +// Time complexity: O(n^2) +// Space complexity: O(n) +func ThreeSumHashMap(nums []int) [][]int { + n := len(nums) + result := map[[3]int]bool{} + + for i := 0; i < n; i++ { + target := -nums[i] + seen := map[int]bool{} + for j := i + 1; j < n; j++ { + complement := target - nums[j] + if seen[complement] { + triplet := []int{nums[i], nums[j], complement} + sort.Ints(triplet) + var key [3]int + copy(key[:], triplet) + result[key] = true + } + seen[nums[j]] = true + } + } + + // convert map to slice - initialize empty slice to avoid nil + output := make([][]int, 0) + for k := range result { + output = append(output, []int{k[0], k[1], k[2]}) + } + return output +} + +// Time complexity: O(n^2) +// Space complexity: O(1) +func ThreeSumTwoPointers(nums []int) [][]int { + sort.Ints(nums) + n := len(nums) + result := make([][]int, 0) // Initialize empty slice to avoid nil + + for i := 0; i < n-2; i++ { + // Skip duplicates + if i > 0 && nums[i] == nums[i-1] { + continue + } + left := i + 1 + right := n - 1 + + for left < right { + sum := nums[i] + nums[left] + nums[right] + + if sum == 0 { + result = append(result, []int{nums[i], nums[left], nums[right]}) + + // Skip duplicates + for left < right && nums[left] == nums[left+1] { + left++ + } + for left < right && nums[right] == nums[right-1] { + right-- + } + + left++ + right-- + } else if sum < 0 { + left++ + } else { + right-- + } + } + } + + return result +} diff --git a/2_two_pointers/3_3sum/solution_test.go b/2_two_pointers/3_3sum/solution_test.go new file mode 100644 index 0000000..0327205 --- /dev/null +++ b/2_two_pointers/3_3sum/solution_test.go @@ -0,0 +1,67 @@ +package sum + +import ( + "reflect" + "sort" + "testing" +) + +func sortTriplets(triplets [][]int) { + for _, triplet := range triplets { + sort.Ints(triplet) + } + sort.Slice(triplets, func(i, j int) bool { + for k := 0; k < 3; k++ { + if triplets[i][k] != triplets[j][k] { + return triplets[i][k] < triplets[j][k] + } + } + return false + }) +} + +func TestThreeSum(t *testing.T) { + cases := []struct { + name string + fn func([]int) [][]int + nums []int + expected [][]int + }{ + // ThreeSumBruteForce + {"Brute Force - Typical case with multiple triplets", ThreeSumBruteForce, []int{-1, 0, 1, 2, -1, -4}, [][]int{{-1, -1, 2}, {-1, 0, 1}}}, + {"Brute Force - All zeroes", ThreeSumBruteForce, []int{0, 0, 0, 0}, [][]int{{0, 0, 0}}}, + {"Brute Force - No valid triplet", ThreeSumBruteForce, []int{1, 2, -2, -1}, [][]int{}}, + {"Brute Force - Empty array", ThreeSumBruteForce, []int{}, [][]int{}}, + {"Brute Force - Single element", ThreeSumBruteForce, []int{1}, [][]int{}}, + {"Brute Force - Two elements", ThreeSumBruteForce, []int{1, 2}, [][]int{}}, + + // HashMap + {"Hash Map - Typical case with multiple triplets", ThreeSumHashMap, []int{-1, 0, 1, 2, -1, -4}, [][]int{{-1, -1, 2}, {-1, 0, 1}}}, + {"Hash Map - All zeroes", ThreeSumHashMap, []int{0, 0, 0, 0}, [][]int{{0, 0, 0}}}, + {"Hash Map - No valid triplet", ThreeSumHashMap, []int{1, 2, -2, -1}, [][]int{}}, + {"Hash Map - Empty array", ThreeSumHashMap, []int{}, [][]int{}}, + {"Hash Map - Single element", ThreeSumHashMap, []int{1}, [][]int{}}, + {"Hash Map - Two elements", ThreeSumHashMap, []int{1, 2}, [][]int{}}, + + // TwoPointers + {"Two Pointers - Typical case with multiple triplets", ThreeSumTwoPointers, []int{-1, 0, 1, 2, -1, -4}, [][]int{{-1, -1, 2}, {-1, 0, 1}}}, + {"Two Pointers - All zeroes", ThreeSumTwoPointers, []int{0, 0, 0, 0}, [][]int{{0, 0, 0}}}, + {"Two Pointers - No valid triplet", ThreeSumTwoPointers, []int{1, 2, -2, -1}, [][]int{}}, + {"Two Pointers - Empty array", ThreeSumTwoPointers, []int{}, [][]int{}}, + {"Two Pointers - Single element", ThreeSumTwoPointers, []int{1}, [][]int{}}, + {"Two Pointers - Two elements", ThreeSumTwoPointers, []int{1, 2}, [][]int{}}, + {"Two Pointers - Large numbers", ThreeSumTwoPointers, []int{-4, -1, -1, 0, 1, 2}, [][]int{{-1, -1, 2}, {-1, 0, 1}}}, + {"Two Pointers - Duplicates with valid triplet", ThreeSumTwoPointers, []int{-2, 0, 0, 2, 2}, [][]int{{-2, 0, 2}}}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := c.fn(c.nums) + sortTriplets(got) + sortTriplets(c.expected) + if !reflect.DeepEqual(got, c.expected) { + t.Errorf("%s failed: expected %v, got %v", c.name, c.expected, got) + } + }) + } +}