ARTS 打卡week06
每周完成一个 ARTS:
Algorithm: 每周至少做一个 LeetCode 的算法题
Review: 阅读并点评至少一篇英文技术文章
Tips: 学习至少一个技术技巧
Share: 分享一篇有观点和思考的技术文章
Algorithm
15. 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,
使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
解析
0015_three_sum.go
// ans_1: Exhaustive method (encounter timeout)
func ThreeSum01(nums []int) [][]int {
flagI, res := false, [][]int{}
sort.Ints(nums)
for i, _ := range nums {
// repeat element ignore
if flagI == true && nums[i] == nums[i-1] {
continue
}
if !flagI {
flagI = true
}
// flagJ should be initialized after a loop
flagJ := false
for j, _ := range nums {
// repeat element ignore
if j <= i || (flagJ == true && nums[j] == nums[j-1]){
continue
}
if !flagJ {
flagJ = true
}
flagK := false
for k, _ := range nums {
if k <= j || (flagK == true && nums[k] == nums[k-1]){
continue
}
if !flagK {
flagK = true
}
if nums[i] + nums[j] + nums[k] == 0 {
res = append(res, []int{nums[i], nums[j], nums[k]})
}
}
}
}
return res
}
// ans_2: use the property of c = -(a + b)
// create a map and store sorted nums elements
// enumerate a, b value, if -(a+b) exists in map, store elements into res
// caution: remove repeate result
func ThreeSum02(nums []int) [][]int {
sort.Ints(nums)
res := [][]int{}
set := make(map[int]int, len(nums))
for index, value := range nums {
set[value] = index
}
for i, valueI := range nums {
// remove repeat result
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j, valueJ := range nums {
// remove repeat result
if j <= i || (j > i + 1 && nums[j] == nums[j-1]) {
continue
}
// remove repeat result
if value, ok := set[-(valueI+valueJ)]; ok && value > j {
res = append(res, []int{valueI, valueJ, -(valueI+valueJ)})
}
}
}
return res
}
// ans_3: use left index and right index
func ThreeSum03(nums []int) [][]int {
sort.Ints(nums)
res := [][]int{}
set := make(map[int]int, len(nums))
for index, value := range nums {
set[value] = index
}
for i, value := range nums {
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j, k := i+1, len(nums)-1; j < k; {
switch {
case value+nums[j]+nums[k] > 0:
k--
case value+nums[j]+nums[k] < 0:
j++
default:
res = append(res, []int{nums[i], nums[j], nums[k]})
I:
for j < k {
switch {
case nums[j] == nums[j+1]:
j++
case nums[k] == nums[k-1]:
k--
default:
j++
k--
break I
}
}
}
}
}
return res
}
0015_three_sum.go
package leetCode
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)
type question0015 struct {
para0015
ans0015
}
// para0015 是参数
// one 代表第一个参数
type para0015 struct {
one []int
}
// ans0015 是答案
// one 代表第一个答案
type ans0015 struct {
one [][]int
}
func Test_Problem0015(t *testing.T) {
ast := assert.New(t)
qs := []question0015{
question0015{
para0015{[]int{-1,0,1,2,-1,-4}},
ans0015{[][]int{
[]int{-1, 0, 1},
[]int{-1, -1, 2},
}},
},
// 如需多个测试,可以复制上方元素。
}
for _, q := range qs {
a, p := q.ans0015, q.para0015
ast.Equal(a.one, ThreeSum03(p.one), "输入:%v", p)
fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
}
}
Review
Tips
-
for range 结构是Go语言特有的一种的迭代结构,在许多情况下都非常有用,for range 可以遍历数组、切片、字符串、map 及通道(channel),for range 语法上类似于其它语言中的 foreach 语句,一般形式为:
for key, val := range coll { ... }
-
通过 for range 遍历的返回值有一定的规律:
/* - 数组、切片、字符串返回索引和值。 - map 返回键和值。 - 通道(channel)只返回通道内的值。 */ for key, value := range []int{1, 2, 3, 4} { fmt.Printf("key:%d value:%d\n", key, value) } var str = "hello 你好" for key, value := range str { fmt.Printf("key:%d value:0x%x\n", key, value) } m := map[string]int{ "hello": 100, "world": 200, } for key, value := range m { fmt.Println(key, value) } c := make(chan int) go func() { c <- 1 c <- 2 c <- 3 close(c) }() for v := range c { fmt.Println(v) }
注:
这里的 value 映射的值使用的是同一个地址,而不是直接返回每个元素的应用,如果使用该变量的地址作为指向的每个元素的指针,会出错。
for range 元素的顺序为 index, value (fuck, 经常忘记顺序)
-
map 遍历时顺序不固定
func main() { m := map[string]string{ "1": "1", "2": "2", "3": "3", } for k, v := range m { println(k, v) } }