Skip to content

Commit 36625f5

Browse files
committed
init commit
0 parents  commit 36625f5

File tree

8 files changed

+316
-0
lines changed

8 files changed

+316
-0
lines changed

.github/workflows/go.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Go
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
build_and_test:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v3
17+
- name: Setup Go
18+
uses: actions/setup-go@v3
19+
with:
20+
go-version: 1.16
21+
- name: Build
22+
run: go build -v ./...
23+
- name: Test
24+
run: go test -v -cover ./...
25+
- name: BenchmarkTest
26+
run: go test -benchmem -run=none -bench ^BenchmarkTest sol/sol

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Output of the go coverage tool, specifically when used with LiteIDE
15+
*.out
16+
17+
# Dependency directories (remove the comment below to include it)
18+
# vendor/
19+
20+
# Go workspace file
21+
go.work

.gitlab-ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
stages:
2+
- test
3+
build and test:
4+
image: golang:1.16
5+
stage: test
6+
script:
7+
- go build -v ./...
8+
- go test -v -cover ./...
9+
- go test -benchmem -run=none -bench ^BenchmarkTest sol/sol

.husky/pre-commit

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
go test -v -cover ./...

README.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# golang_three_sum
2+
3+
Given an integer array nums, return all the triplets `[nums[i], nums[j], nums[k]]` such that `i != j``i != k`, and `j != k`, and `nums[i] + nums[j] + nums[k] == 0`.
4+
5+
Notice that the solution set must not contain duplicate triplets.
6+
7+
## Examples
8+
9+
**Example 1:**
10+
11+
```
12+
Input: nums = [-1,0,1,2,-1,-4]
13+
Output: [[-1,-1,2],[-1,0,1]]
14+
Explanation:
15+
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
16+
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
17+
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
18+
The distinct triplets are [-1,0,1] and [-1,-1,2].
19+
Notice that the order of the output and the order of the triplets does not matter.
20+
21+
```
22+
23+
**Example 2:**
24+
25+
```
26+
Input: nums = [0,1,1]
27+
Output: []
28+
Explanation: The only possible triplet does not sum up to 0.
29+
30+
```
31+
32+
**Example 3:**
33+
34+
```
35+
Input: nums = [0,0,0]
36+
Output: [[0,0,0]]
37+
Explanation: The only possible triplet sums up to 0.
38+
39+
```
40+
41+
**Constraints:**
42+
43+
- `3 <= nums.length <= 3000`
44+
- $`-10^5$ <= nums[i] <= $10^5$`
45+
46+
## 解析
47+
48+
給定一個整數陣列 nums
49+
50+
要求寫一個演算法找在所有在 nums 中3個和= 0 數字的所有不重複複組合
51+
52+
已知目標是找到 i, j , k , i < j < k , 使得 nums[i] + nums[j] + nums[k] =0
53+
54+
可以注意到 當 nums[j] 確定時, nums[i] + nums[k] 只能 - nums[j]
55+
56+
所以可透過 類似 two sum 的作法
57+
58+
另外為了可以使用 two pointer 來縮小範圍
59+
60+
所以將原本的nums 做 sort 來做由小到大的排列
61+
62+
初始化 start = 0, index = 1, end = len(nums) - 1, result = []
63+
64+
當針對所有可能的 index 做檢查(使用 two pointer)
65+
66+
![](https://i.imgur.com/D9AOUSA.png)
67+
68+
為了避免重複檢查
69+
70+
所以如果 nums[index] = nums[index-1] 時 且 index > 1 代表已經nums[index]找過了
71+
72+
這時需要把 start = index - 1 讓搜索範圍變小
73+
74+
而對於 start < index 且 end > index 時
75+
76+
為了避免重複檢查
77+
78+
當nums[start] = nums[start-1] 且 start > 0 代表此搜索範圍已經找過了
79+
80+
這時需要把 start += 1 重新搜索
81+
82+
當nums[end] = nums[end+1] 且 end < len(nums) - 1 代表此搜索範圍已經找過了
83+
84+
這時需要把 end -= 1 重新搜索
85+
86+
令 addNum = nums[start] + nums[index] + nums[end]
87+
88+
當 addNum = 0 代表找到符合條件的組合
89+
90+
[nums[start], nums[index], nums[end]] 加入 result , 更新 start += 1, end -= 1
91+
92+
當 addNum > 0 因為 start 已經是最小值 所以只能把 end 往左移
93+
94+
更新 end -= 1
95+
96+
當 addNum < 0 因為 end 已經是最大值 所以只能把 start 往右移
97+
98+
更新 start += 1
99+
100+
## 程式碼
101+
```go
102+
package sol
103+
104+
import "sort"
105+
106+
func threeSum(nums []int) [][]int {
107+
if len(nums) < 3 {
108+
return [][]int{}
109+
}
110+
result := [][]int{}
111+
sort.Ints(nums)
112+
n := len(nums)
113+
// fixed index pivot
114+
for pivot := 1; pivot < n-1; pivot++ {
115+
start, end := 0, n-1
116+
// do two sum for fixed index pivot
117+
if pivot > 1 && nums[pivot] == nums[pivot-1] {
118+
start = pivot - 1
119+
}
120+
for start < pivot && pivot < end {
121+
if start > 0 && nums[start] == nums[start-1] { // update search range
122+
start++
123+
continue
124+
}
125+
if end < n-1 && nums[end] == nums[end+1] { // update search range
126+
end--
127+
continue
128+
}
129+
sum := nums[start] + nums[pivot] + nums[end]
130+
if sum == 0 {
131+
result = append(result, []int{nums[start], nums[pivot], nums[end]})
132+
start++
133+
end--
134+
} else if sum > 0 {
135+
end--
136+
} else {
137+
start++
138+
}
139+
}
140+
}
141+
return result
142+
}
143+
144+
```
145+
## 困難點
146+
147+
1. 需要想出避免重複的方法
148+
2. 需要想出對邊界值移動的條件
149+
150+
## Solve Point
151+
152+
- [x] 初始化 i = 1 , result = []
153+
- [x] 針對每個 i = 1.. len(nums)-1 做以下檢查
154+
- [x] 初始化 start = 0, end = len(nums) - 1
155+
- [x] 當 i > 1 且 num[i] == nums[i-1] 代表此數值已經搜尋過, 則更新 start = i - 1
156+
- [x] 當 i > start 且 i < end 做以下檢查
157+
- [x] 如果 start > 0 且 nums[start-1] = nums[start] 代表此範圍已經搜尋過,更新 start += 1 重新搜尋
158+
- [x] 如果 end < len(nums) - 1 且 nums[end+1] = nums[end] 代表此範圍已經搜尋過,更新 end-= 1 重新搜尋
159+
- [x] 令 addNum = nums[start] + nums[i] + nums[end]
160+
- [x] 當 addNum == 0 時 , 新增 [nums[start], nums[i], nums[end]], 更新 start+=1, end -= 1, 繼續搜尋
161+
- [x] 當 addNum > 0 時 , 因為 start 已經是最小值所以只能把 end 左移, 更新 end -= 1, 繼續搜尋
162+
- [x] 當 addNum < 0 時 , 因為 end 已經是最大值所以只能把 start 右移, 更新 start += 1, 繼續搜尋
163+
- [x] 回傳 result

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module sol
2+
3+
go 1.16

sol/solution.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package sol
2+
3+
import "sort"
4+
5+
func threeSum(nums []int) [][]int {
6+
if len(nums) < 3 {
7+
return [][]int{}
8+
}
9+
result := [][]int{}
10+
sort.Ints(nums)
11+
n := len(nums)
12+
// fixed index pivot
13+
for pivot := 1; pivot < n-1; pivot++ {
14+
start, end := 0, n-1
15+
// do two sum for fixed index pivot
16+
if pivot > 1 && nums[pivot] == nums[pivot-1] {
17+
start = pivot - 1
18+
}
19+
for start < pivot && pivot < end {
20+
if start > 0 && nums[start] == nums[start-1] { // update search range
21+
start++
22+
continue
23+
}
24+
if end < n-1 && nums[end] == nums[end+1] { // update search range
25+
end--
26+
continue
27+
}
28+
sum := nums[start] + nums[pivot] + nums[end]
29+
if sum == 0 {
30+
result = append(result, []int{nums[start], nums[pivot], nums[end]})
31+
start++
32+
end--
33+
} else if sum > 0 {
34+
end--
35+
} else {
36+
start++
37+
}
38+
}
39+
}
40+
return result
41+
}

sol/solution_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package sol
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func BenchmarkTest(b *testing.B) {
9+
nums := []int{-1, 0, 1, 2, -1, -4}
10+
for idx := 0; idx < b.N; idx++ {
11+
threeSum(nums)
12+
}
13+
}
14+
func Test_threeSum(t *testing.T) {
15+
type args struct {
16+
nums []int
17+
}
18+
tests := []struct {
19+
name string
20+
args args
21+
want [][]int
22+
}{
23+
{
24+
name: "nums = [-1,0,1,2,-1,-4]",
25+
args: args{nums: []int{-1, 0, 1, 2, -1, -4}},
26+
want: [][]int{{-1, -1, 2}, {-1, 0, 1}},
27+
},
28+
{
29+
name: "nums = [0,1,1]",
30+
args: args{nums: []int{0, 1, 1}},
31+
want: [][]int{},
32+
},
33+
{
34+
name: "nums = [0,0,0]",
35+
args: args{nums: []int{0, 0, 0}},
36+
want: [][]int{{0, 0, 0}},
37+
},
38+
{
39+
name: "nums = [-2,0,1,1,2]",
40+
args: args{nums: []int{-2, 0, 1, 1, 2}},
41+
want: [][]int{{-2, 0, 2}, {-2, 1, 1}},
42+
},
43+
}
44+
for _, tt := range tests {
45+
t.Run(tt.name, func(t *testing.T) {
46+
if got := threeSum(tt.args.nums); !reflect.DeepEqual(got, tt.want) {
47+
t.Errorf("threeSum() = %v, want %v", got, tt.want)
48+
}
49+
})
50+
}
51+
}

0 commit comments

Comments
 (0)