├── 单调栈 └── main.go ├── .gitignore ├── 0001_two_sum └── two_sum.go ├── concurrency ├── runnable.go └── token.go ├── stack.go ├── 0003_longest_substring_without_repeating_characters └── longest_substring_without_repeating_characters.go ├── 0005_longest_palindromic_substring └── longest_palindromic_substring.go ├── 广度优先和深度优先 ├── tree_test.go └── tree.go ├── 0014_longest_common_prefix └── longest_common_prefix.go ├── 0004_median_of_two_sorted_arrays └── median_of_two_sorted_arrays.go ├── 0002_add_two_numbers └── add_two_numbers.go ├── 1117_building_h2o ├── water.go └── water_test.go ├── LICENSE ├── 1115_print_foobar_alternately └── foobar.go ├── 0084-largest-rectangle-in-histogram └── largest-rectangle-in-histogram.go ├── 1116_print_zero_even_odd └── zero_even_odd.go ├── 1195_fizz_buzz_multithreaded └── fizz_buzz.go └── 二叉搜索树 ├── bst_test.go └── bst.go /单调栈/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | -------------------------------------------------------------------------------- /0001_two_sum/two_sum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | 7 | // 从整数数组中找到两个数,相加得到目标值. 8 | // TAG: 哈希表, O(n) 9 | // 思路: 对扫过的数据通过一个哈希表记录下来,方便后续的数查找 10 | func twoSum(nums []int, target int) []int { 11 | m := make(map[int]int, len(nums)) 12 | 13 | for i := 0; i < len(nums); i++ { 14 | complement := target - nums[i] 15 | if index, ok := m[complement]; ok { 16 | return []int{index, i} 17 | } 18 | m[nums[i]] = i 19 | } 20 | 21 | return nil 22 | } 23 | -------------------------------------------------------------------------------- /concurrency/runnable.go: -------------------------------------------------------------------------------- 1 | package co 2 | 3 | import "fmt" 4 | 5 | // Runnable is a simple function. 6 | type Runnable func() 7 | 8 | // Accept accepts a integer and print something. 9 | type Accept func(x int) 10 | 11 | // WrapPrint wraps `fmt.Print(s)` as Runnable. 12 | func WrapPrint(s string) Runnable { 13 | return func() { 14 | fmt.Print(s) 15 | } 16 | } 17 | 18 | // WrapPrintln wraps `fmt.Println(s)` as Runnable. 19 | func WrapPrintln(s string) Runnable { 20 | return func() { 21 | fmt.Println(s) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /stack.go: -------------------------------------------------------------------------------- 1 | package leetcode 2 | 3 | type IntStack []int 4 | 5 | func (s *IntStack) IsEmpty() bool { 6 | return len(*s) == 0 7 | } 8 | 9 | func (s *IntStack) Top() (int, bool) { 10 | if s.IsEmpty() { 11 | return 0, false 12 | } else { 13 | return (*s)[len(*s)-1], true 14 | } 15 | } 16 | 17 | func (s *IntStack) Push(e int) { 18 | *s = append(*s, e) 19 | } 20 | 21 | func (s *IntStack) Pop() (int, bool) { 22 | if s.IsEmpty() { 23 | return 0, false 24 | } else { 25 | index := len(*s) - 1 26 | element := (*s)[index] 27 | *s = (*s)[:index] 28 | return element, true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /concurrency/token.go: -------------------------------------------------------------------------------- 1 | package co 2 | 3 | // Coordinator creates a coordinator to handle handoff case. 4 | type Coordinator struct { 5 | chans []chan struct{} 6 | } 7 | 8 | // NewCoordinator creates a Coordinator. 9 | func NewCoordinator(n int) *Coordinator { 10 | chans := make([]chan struct{}, n) 11 | for i := 0; i < n; i++ { 12 | chans[i] = make(chan struct{}, 1) 13 | } 14 | 15 | return &Coordinator{ 16 | chans: chans, 17 | } 18 | } 19 | 20 | // Accquire accquires the token. 21 | func (coo *Coordinator) Accquire(i int) { 22 | <-coo.chans[i] 23 | } 24 | 25 | // Handoff passes the token to i. 26 | func (coo *Coordinator) Handoff(i int) { 27 | coo.chans[i] <- struct{}{} 28 | } 29 | -------------------------------------------------------------------------------- /0003_longest_substring_without_repeating_characters/longest_substring_without_repeating_characters.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | 7 | // 不带重复字母的最长子串. (子字符串substring,不是子序列subsequence) 8 | // TAG: O(n) 9 | // 思路: 使用数组记录已发现字符的当前位置。使用两个指针start, i移动,当前的搜寻范围为(start,i)的字符串 10 | func lengthOfLongestSubstring(s string) int { 11 | if len(s) == 0 { 12 | return 0 13 | } 14 | 15 | var m = make(map[byte]int, 256) 16 | 17 | maxLen := 0 18 | start := -1 19 | for i := 0; i < len(s); i++ { 20 | if j, ok := m[s[i]]; ok { 21 | if j > start { // 在本次的搜寻范围内 22 | start = j 23 | } 24 | } 25 | m[s[i]] = i 26 | if i-start > maxLen { 27 | maxLen = i - start 28 | } 29 | } 30 | return maxLen 31 | } 32 | -------------------------------------------------------------------------------- /0005_longest_palindromic_substring/longest_palindromic_substring.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | s := "babad" 7 | fmt.Println(longestPalindrome(s)) 8 | } 9 | 10 | func longestPalindrome(s string) string { 11 | if len(s) < 2 { 12 | return s 13 | } 14 | 15 | var l = len(s) 16 | var begin int 17 | var maxLen int 18 | 19 | for i := 0; i < l-maxLen/2; i++ { 20 | var j = i 21 | var k = i 22 | 23 | for k < l-1 && s[k] == s[k+1] { 24 | k++ 25 | } 26 | 27 | // 注意两个端点 28 | for j > 0 && k < l-1 && s[j-1] == s[k+1] { 29 | j-- 30 | k++ 31 | } 32 | 33 | newLen := k - j + 1 34 | if newLen > maxLen { 35 | begin = j 36 | maxLen = newLen 37 | } 38 | } 39 | 40 | return s[begin : begin+maxLen] 41 | } 42 | -------------------------------------------------------------------------------- /广度优先和深度优先/tree_test.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestTree_BFS(t *testing.T) { 9 | root := &Node{ 10 | 100, 11 | []*Node{ 12 | {20, []*Node{ 13 | {77, nil}, 14 | }}, 15 | {57, nil}, 16 | {210, []*Node{ 17 | {98, nil}, 18 | {10, nil}, 19 | }}, 20 | }, 21 | } 22 | 23 | tree := &Tree{root} 24 | 25 | ans := tree.BFS() 26 | 27 | fmt.Println(ans) 28 | } 29 | 30 | func TestTree_DFS(t *testing.T) { 31 | root := &Node{ 32 | 100, 33 | []*Node{ 34 | {20, []*Node{ 35 | {77, nil}, 36 | }}, 37 | {57, nil}, 38 | {210, []*Node{ 39 | {98, nil}, 40 | {10, nil}, 41 | }}, 42 | }, 43 | } 44 | 45 | tree := &Tree{root} 46 | 47 | ans := tree.DFS() 48 | 49 | fmt.Println(ans) 50 | } 51 | -------------------------------------------------------------------------------- /0014_longest_common_prefix/longest_common_prefix.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | var strs = []string{"flower", "flow", "flight"} 11 | fmt.Println(longestCommonPrefix(strs)) 12 | } 13 | 14 | func longestCommonPrefix(strs []string) string { 15 | if len(strs) == 0 { 16 | return "" 17 | } 18 | 19 | var rt strings.Builder 20 | 21 | var min int = int(math.MaxInt64) 22 | var lens = make([]int, len(strs)) 23 | for i := 0; i < len(strs); i++ { 24 | lens[i] = len(strs[i]) 25 | if lens[i] < min { 26 | min = lens[i] 27 | } 28 | } 29 | 30 | for i := 0; i < min; i++ { 31 | c := strs[0][i] 32 | for j := 1; j < len(strs); j++ { 33 | if strs[j][i] != c { 34 | return rt.String() 35 | } 36 | } 37 | rt.WriteByte(c) 38 | } 39 | 40 | return rt.String() 41 | } 42 | -------------------------------------------------------------------------------- /0004_median_of_two_sorted_arrays/median_of_two_sorted_arrays.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | 7 | // 寻找两个已排序数组的中位数. 8 | // TAG: O(n) 9 | func findMedianSortedArrays(nums1 []int, nums2 []int) float64 { 10 | 11 | m := len(nums1) 12 | n := len(nums2) 13 | num := make([]int, m+n, m+n) 14 | t := (m + n) / 2 15 | 16 | var i, j, k int 17 | for i < m && j < n && k <= t { 18 | if nums1[i] <= nums2[j] { 19 | num[k] = nums1[i] 20 | i = i + 1 21 | } else { 22 | num[k] = nums2[j] 23 | j = j + 1 24 | } 25 | k = k + 1 26 | } 27 | 28 | for i < m && k <= t { 29 | num[k] = nums1[i] 30 | i = i + 1 31 | k = k + 1 32 | } 33 | 34 | for j < n && k <= t { 35 | num[k] = nums2[j] 36 | j = j + 1 37 | k = k + 1 38 | } 39 | 40 | if t*2 < (m + n) { 41 | return float64(num[t]) 42 | } 43 | return float64(num[t-1]+num[t]) / 2 44 | 45 | } 46 | -------------------------------------------------------------------------------- /0002_add_two_numbers/add_two_numbers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | 7 | type ListNode struct { 8 | Val int 9 | Next *ListNode 10 | } 11 | 12 | // 模拟加法. 13 | // TAG: 链表, O(n) 14 | func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { 15 | if l1 == nil || l2 == nil { 16 | return nil 17 | } 18 | 19 | var carry int 20 | var head = &ListNode{} 21 | 22 | var ln = head 23 | for l1 != nil || l2 != nil { 24 | v := carry 25 | if l1 != nil { 26 | v += l1.Val 27 | l1 = l1.Next 28 | } 29 | if l2 != nil { 30 | v += l2.Val 31 | l2 = l2.Next 32 | } 33 | 34 | // 计算当前的值和进位 35 | if v > 9 { 36 | v = v - 10 37 | carry = 1 38 | } else { 39 | carry = 0 40 | } 41 | 42 | ln.Next = &ListNode{Val: v} 43 | ln = ln.Next 44 | } 45 | 46 | if carry == 1 { 47 | ln.Next = &ListNode{Val: 1} 48 | } 49 | 50 | return head.Next 51 | } 52 | -------------------------------------------------------------------------------- /1117_building_h2o/water.go: -------------------------------------------------------------------------------- 1 | package water 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/marusama/cyclicbarrier" 7 | "golang.org/x/sync/semaphore" 8 | ) 9 | 10 | type H2O struct { 11 | semaH *semaphore.Weighted 12 | semaO *semaphore.Weighted 13 | b cyclicbarrier.CyclicBarrier 14 | } 15 | 16 | func New() *H2O { 17 | return &H2O{ 18 | semaH: semaphore.NewWeighted(2), 19 | semaO: semaphore.NewWeighted(1), 20 | b: cyclicbarrier.New(3), 21 | } 22 | } 23 | 24 | func (h2o *H2O) hydrogen(releaseHydrogen func()) { 25 | h2o.semaH.Acquire(context.Background(), 1) 26 | 27 | // releaseHydrogen() outputs "H". Do not change or remove this line. 28 | releaseHydrogen() 29 | h2o.b.Await(context.Background()) 30 | 31 | h2o.semaH.Release(1) 32 | } 33 | 34 | func (h2o *H2O) oxygen(releaseOxygen func()) { 35 | h2o.semaO.Acquire(context.Background(), 1) 36 | 37 | // releaseOxygen() outputs "O". Do not change or remove this line. 38 | releaseOxygen() 39 | h2o.b.Await(context.Background()) 40 | 41 | h2o.semaO.Release(1) 42 | } 43 | -------------------------------------------------------------------------------- /广度优先和深度优先/tree.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | type Node struct { 4 | value int 5 | children []*Node 6 | } 7 | 8 | type Tree struct { 9 | root *Node 10 | } 11 | 12 | // BFS breadth first search 13 | func (t *Tree) BFS() []int { 14 | var ans []int 15 | 16 | // 待搜索队列 17 | var queue []*Node 18 | 19 | if t.root == nil { 20 | return nil 21 | } 22 | 23 | // 先把root加入到待处理队列 24 | queue = append(queue, t.root) 25 | 26 | for len(queue) > 0 { 27 | ans = append(ans, queue[0].value) 28 | 29 | // 把此节点的所有子节点加入到队列中 30 | for _, child := range queue[0].children { 31 | queue = append(queue, child) 32 | } 33 | 34 | queue = queue[1:] 35 | } 36 | 37 | return ans 38 | } 39 | 40 | // DFS Depth first search 41 | func (t *Tree) DFS() []int { 42 | if t.root == nil { 43 | return nil 44 | } 45 | 46 | var ans []int 47 | return dfs(t.root, ans) 48 | } 49 | 50 | func dfs(root *Node, rt []int) []int { 51 | rt = append(rt, root.value) 52 | 53 | // 深度优先搜索 54 | for _, child := range root.children { 55 | rt = dfs(child, rt) 56 | } 57 | 58 | return rt 59 | } 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 smallnest 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /1115_print_foobar_alternately/foobar.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync" 7 | 8 | "github.com/smallnest/syncx" 9 | ) 10 | 11 | type Runnable func() 12 | 13 | type FooBar struct { 14 | n int 15 | token *syncx.Token 16 | } 17 | 18 | func (fb FooBar) foo(printFoo Runnable) { 19 | for i := 0; i < fb.n; i++ { 20 | fb.token.Accquire(context.TODO(), 0) 21 | printFoo() 22 | fb.token.Handoff(context.TODO(), 1) 23 | } 24 | } 25 | 26 | func (fb FooBar) bar(printBar Runnable) { 27 | for i := 0; i < fb.n; i++ { 28 | fb.token.Accquire(context.TODO(), 1) 29 | printBar() 30 | fb.token.Handoff(context.TODO(), 0) 31 | } 32 | } 33 | 34 | func main() { 35 | printFoo := func() { 36 | fmt.Print("foo") 37 | } 38 | printBar := func() { 39 | fmt.Print("bar") 40 | } 41 | 42 | var wg sync.WaitGroup 43 | wg.Add(2) 44 | 45 | token := syncx.NewToken(2) 46 | foobar := FooBar{n: 10, token: token} 47 | 48 | go func() { 49 | foobar.foo(printFoo) 50 | wg.Done() 51 | }() 52 | go func() { 53 | foobar.bar(printBar) 54 | wg.Done() 55 | }() 56 | 57 | // trigger to start 58 | token.Handoff(context.TODO(), 0) 59 | wg.Wait() 60 | } 61 | -------------------------------------------------------------------------------- /0084-largest-rectangle-in-histogram/largest-rectangle-in-histogram.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | 7 | func largestRectangleArea(heights []int) int { 8 | n := len(heights) 9 | left, right := make([]int, n), make([]int, n) 10 | for i := 0; i < n; i++ { 11 | right[i] = n 12 | } 13 | 14 | //单调栈 15 | mono_stack := []int{} 16 | // 从头开始遍历 17 | for i := 0; i < n; i++ { 18 | // 如果栈内有数据,并且栈顶的值比当前的值大, 破坏了单调, 19 | // 那么找到左边比当前值小的第一个值 20 | for len(mono_stack) > 0 && heights[mono_stack[len(mono_stack)-1]] >= heights[i] { 21 | right[mono_stack[len(mono_stack)-1]] = i //保存比栈顶的的值小的第一个右边的位置 22 | mono_stack = mono_stack[:len(mono_stack)-1] // 弹出栈顶 23 | } 24 | 25 | // 记录比当前值小的第一个值的位置 26 | if len(mono_stack) == 0 { 27 | left[i] = -1 28 | } else { 29 | left[i] = mono_stack[len(mono_stack)-1] 30 | } 31 | 32 | // 将当前的值押入到栈中 33 | mono_stack = append(mono_stack, i) 34 | } 35 | ans := 0 36 | 37 | // 已经得到了每个元素的左边界和右边界,左右边界相减,减1乘以高度就是这个元素所在的矩形的最大面积 38 | for i := 0; i < n; i++ { 39 | ans = max(ans, (right[i]-left[i]-1)*heights[i]) 40 | } 41 | return ans 42 | } 43 | 44 | func max(x, y int) int { 45 | if x > y { 46 | return x 47 | } 48 | return y 49 | } 50 | -------------------------------------------------------------------------------- /1116_print_zero_even_odd/zero_even_odd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync" 7 | 8 | "github.com/smallnest/syncx" 9 | ) 10 | 11 | type Accept func(x int) 12 | 13 | type ZeroEvenOdd struct { 14 | n int 15 | token *syncx.Token 16 | } 17 | 18 | func (zeo *ZeroEvenOdd) zero(accept Accept) { 19 | for i := 1; i <= zeo.n; i++ { 20 | zeo.token.Accquire(context.TODO(), 0) 21 | accept(0) 22 | if i%2 == 0 { 23 | zeo.token.Handoff(context.TODO(), 1) 24 | } else { 25 | zeo.token.Handoff(context.TODO(), 2) 26 | } 27 | } 28 | 29 | } 30 | 31 | func (zeo *ZeroEvenOdd) even(accept Accept) { 32 | for i := 0; i < zeo.n/2; i++ { 33 | zeo.token.Accquire(context.TODO(), 1) 34 | accept((i + 1) * 2) 35 | zeo.token.Handoff(context.TODO(), 0) 36 | } 37 | } 38 | 39 | func (zeo *ZeroEvenOdd) odd(accept Accept) { 40 | for i := 0; i < (zeo.n+1)/2; i++ { 41 | zeo.token.Accquire(context.TODO(), 2) 42 | accept(i*2 + 1) 43 | zeo.token.Handoff(context.TODO(), 0) 44 | } 45 | } 46 | 47 | func main() { 48 | accept := func(x int) { fmt.Print(x) } 49 | 50 | var wg sync.WaitGroup 51 | wg.Add(3) 52 | 53 | token := syncx.NewToken(3) 54 | zeo := &ZeroEvenOdd{ 55 | n: 9, 56 | token: token, 57 | } 58 | 59 | go func() { 60 | zeo.zero(accept) 61 | wg.Done() 62 | }() 63 | go func() { 64 | zeo.even(accept) 65 | wg.Done() 66 | }() 67 | go func() { 68 | zeo.odd(accept) 69 | wg.Done() 70 | }() 71 | 72 | // trigger to start 73 | token.Handoff(context.TODO(), 0) 74 | wg.Wait() 75 | } 76 | -------------------------------------------------------------------------------- /1117_building_h2o/water_test.go: -------------------------------------------------------------------------------- 1 | package water 2 | 3 | import ( 4 | "math/rand" 5 | "sort" 6 | "sync" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | func TestWaterFactory(t *testing.T) { 12 | var ch chan string 13 | 14 | releaseHydrogen1 := func() { 15 | ch <- "H" 16 | } 17 | 18 | releaseHydrogen2 := func() { 19 | ch <- "h" 20 | } 21 | 22 | releaseOxygen := func() { 23 | ch <- "O" 24 | } 25 | 26 | var N = 100 27 | ch = make(chan string, N*3) 28 | 29 | h2o := New() 30 | var wg sync.WaitGroup 31 | wg.Add(N * 3) 32 | // h1 33 | go func() { 34 | for i := 0; i < N; i++ { 35 | time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) 36 | h2o.hydrogen(releaseHydrogen1) 37 | wg.Done() 38 | } 39 | }() 40 | 41 | // h2 42 | go func() { 43 | for i := 0; i < N; i++ { 44 | time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) 45 | h2o.hydrogen(releaseHydrogen2) 46 | wg.Done() 47 | } 48 | }() 49 | 50 | // o 51 | go func() { 52 | for i := 0; i < N; i++ { 53 | time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) 54 | h2o.oxygen(releaseOxygen) 55 | wg.Done() 56 | } 57 | }() 58 | 59 | wg.Wait() 60 | 61 | if len(ch) != N*3 { 62 | t.Fatalf("expect %d atom but got %d", N*3, len(ch)) 63 | } 64 | 65 | var s = make([]string, 3) 66 | for i := 0; i < N; i++ { 67 | s[0] = <-ch 68 | s[1] = <-ch 69 | s[2] = <-ch 70 | sort.Strings(s) 71 | 72 | water := s[0] + s[1] + s[2] 73 | if water != "HOh" { 74 | t.Fatalf("expect a water molecule but got %s", water) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /1195_fizz_buzz_multithreaded/fizz_buzz.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | "sync" 9 | 10 | "github.com/smallnest/syncx" 11 | ) 12 | 13 | type Accept func(x int) 14 | 15 | type FizzBuzz struct { 16 | n int 17 | token *syncx.Token 18 | } 19 | 20 | func (fb *FizzBuzz) fizz(printFizz Accept) { 21 | for i := 1; i <= fb.n; i++ { 22 | fb.token.Accquire(context.TODO(), 0) 23 | if i%3 == 0 && i%15 != 0 { 24 | printFizz(i) 25 | } 26 | fb.token.Handoff(context.TODO(), 1) 27 | } 28 | } 29 | 30 | func (fb *FizzBuzz) buzz(printBuzz Accept) { 31 | for i := 1; i <= fb.n; i++ { 32 | fb.token.Accquire(context.TODO(), 1) 33 | if i%5 == 0 && i%15 != 0 { 34 | printBuzz(i) 35 | } 36 | fb.token.Handoff(context.TODO(), 2) 37 | } 38 | } 39 | 40 | func (fb *FizzBuzz) fizzbuzz(printFizzBuzz Accept) { 41 | for i := 1; i <= fb.n; i++ { 42 | fb.token.Accquire(context.TODO(), 2) 43 | if i%15 == 0 { 44 | printFizzBuzz(i) 45 | } 46 | fb.token.Handoff(context.TODO(), 3) 47 | } 48 | } 49 | 50 | func (fb *FizzBuzz) number(printNumber Accept) { 51 | for i := 1; i <= fb.n; i++ { 52 | fb.token.Accquire(context.TODO(), 3) 53 | if i%3 != 0 && i%5 != 0 { 54 | printNumber(i) 55 | } 56 | fb.token.Handoff(context.TODO(), 0) 57 | } 58 | } 59 | 60 | func main() { 61 | var result []string 62 | fizz := func(x int) { result = append(result, "fizz") } 63 | buzz := func(x int) { result = append(result, "buzz") } 64 | fizzbuzz := func(x int) { result = append(result, "fizzbuzz") } 65 | number := func(x int) { result = append(result, strconv.Itoa(x)) } 66 | 67 | var wg sync.WaitGroup 68 | wg.Add(4) 69 | 70 | token := syncx.NewToken(4) 71 | fb := FizzBuzz{ 72 | n: 15, 73 | token: token, 74 | } 75 | 76 | go func() { 77 | fb.fizz(fizz) 78 | wg.Done() 79 | }() 80 | 81 | go func() { 82 | fb.buzz(buzz) 83 | wg.Done() 84 | }() 85 | 86 | go func() { 87 | fb.fizzbuzz(fizzbuzz) 88 | wg.Done() 89 | }() 90 | 91 | go func() { 92 | fb.number(number) 93 | wg.Done() 94 | }() 95 | 96 | // trigger to start 97 | token.Handoff(context.TODO(), 0) 98 | wg.Wait() 99 | 100 | fmt.Println(strings.Join(result, ", ")) 101 | } 102 | -------------------------------------------------------------------------------- /二叉搜索树/bst_test.go: -------------------------------------------------------------------------------- 1 | package bst 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | var bst BST 9 | 10 | func fillTree(bst *BST) { 11 | bst.Insert(8) 12 | bst.Insert(4) 13 | bst.Insert(10) 14 | bst.Insert(2) 15 | bst.Insert(6) 16 | bst.Insert(1) 17 | bst.Insert(3) 18 | bst.Insert(5) 19 | bst.Insert(7) 20 | bst.Insert(9) 21 | } 22 | 23 | func TestInsert(t *testing.T) { 24 | fillTree(&bst) 25 | bst.String() 26 | 27 | bst.Insert(11) 28 | bst.String() 29 | } 30 | 31 | // isSameSlice returns true if the 2 slices are identical 32 | func isSameSlice(a, b []string) bool { 33 | if a == nil && b == nil { 34 | return true 35 | } 36 | if a == nil || b == nil { 37 | return false 38 | } 39 | if len(a) != len(b) { 40 | return false 41 | } 42 | for i := range a { 43 | if a[i] != b[i] { 44 | return false 45 | } 46 | } 47 | return true 48 | } 49 | 50 | func TestInOrderTraverse(t *testing.T) { 51 | var result []string 52 | bst.InOrderTraverse(func(i int) { 53 | result = append(result, fmt.Sprintf("%d", i)) 54 | }) 55 | if !isSameSlice(result, []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}) { 56 | t.Errorf("Traversal order incorrect, got %v", result) 57 | } 58 | } 59 | 60 | func TestPreOrderTraverse(t *testing.T) { 61 | var result []string 62 | bst.PreOrderTraverse(func(i int) { 63 | result = append(result, fmt.Sprintf("%d", i)) 64 | }) 65 | if !isSameSlice(result, []string{"8", "4", "2", "1", "3", "6", "5", "7", "10", "9", "11"}) { 66 | t.Errorf("Traversal order incorrect, got %v instead of %v", result, []string{"8", "4", "2", "1", "3", "6", "5", "7", "10", "9", "11"}) 67 | } 68 | } 69 | 70 | func TestPostOrderTraverse(t *testing.T) { 71 | var result []string 72 | bst.PostOrderTraverse(func(i int) { 73 | result = append(result, fmt.Sprintf("%d", i)) 74 | }) 75 | if !isSameSlice(result, []string{"1", "3", "2", "5", "7", "6", "4", "9", "11", "10", "8"}) { 76 | t.Errorf("Traversal order incorrect, got %v instead of %v", result, []string{"1", "3", "2", "5", "7", "6", "4", "9", "11", "10", "8"}) 77 | } 78 | } 79 | 80 | func TestMin(t *testing.T) { 81 | v, existed := bst.Min() 82 | 83 | if !existed || v != 1 { 84 | t.Errorf("min should be 1") 85 | } 86 | } 87 | 88 | func TestMax(t *testing.T) { 89 | v, existed := bst.Max() 90 | if !existed || v != 11 { 91 | t.Errorf("max should be 11") 92 | } 93 | } 94 | 95 | func TestSearch(t *testing.T) { 96 | if !bst.Search(1) || !bst.Search(8) || !bst.Search(11) { 97 | t.Errorf("search not working") 98 | } 99 | } 100 | 101 | func TestRemove(t *testing.T) { 102 | bst.Remove(1) 103 | 104 | v, existed := bst.Min() 105 | if !existed || v != 2 { 106 | t.Errorf("min should be 2") 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /二叉搜索树/bst.go: -------------------------------------------------------------------------------- 1 | package bst 2 | 3 | import "fmt" 4 | 5 | // 参考 https://flaviocopes.com/golang-data-structure-binary-search-tree/ 6 | 7 | // Node 定义节点. 8 | type Node struct { 9 | value int // 因为目前Go的泛型还没有发布,所以我们这里以一个int具体类型为例 10 | left *Node // 左子节点 11 | right *Node // 右子节点 12 | } 13 | 14 | // BST 是一个节点的值为int类型的二叉搜索树. 15 | type BST struct { 16 | root *Node 17 | } 18 | 19 | // Insert 插入一个元素. 20 | func (bst *BST) Insert(value int) { 21 | newNode := &Node{value, nil, nil} 22 | 23 | // 如果二叉树为空,那么这个节点就当作跟节点 24 | if bst.root == nil { 25 | bst.root = newNode 26 | } else { 27 | insertNode(bst.root, newNode) 28 | } 29 | } 30 | 31 | // 从根节点依次比较 32 | func insertNode(root, newNode *Node) { 33 | if newNode.value < root.value { // 应该放到根节点的左边 34 | if root.left == nil { 35 | root.left = newNode 36 | } else { 37 | insertNode(root.left, newNode) 38 | } 39 | } else if newNode.value > root.value { // 应该放到根节点的右边 40 | if root.right == nil { 41 | root.right = newNode 42 | } else { 43 | insertNode(root.right, newNode) 44 | } 45 | } 46 | 47 | // 否则等于根节点 48 | } 49 | 50 | // Remove 删除一个元素. 51 | func (bst *BST) Remove(value int) bool { 52 | _, existed := remove(bst.root, value) 53 | return existed 54 | } 55 | 56 | // 用来递归移除节点的辅助方法. 57 | // 返回替换root的新节点,以及元素是否存在 58 | func remove(root *Node, value int) (*Node, bool) { 59 | if root == nil { 60 | return nil, false 61 | } 62 | 63 | var existed bool 64 | // 从左边找 65 | if value < root.value { 66 | root.left, existed = remove(root.left, value) 67 | return root, existed 68 | } 69 | 70 | // 从右边找 71 | if value > root.value { 72 | root.right, existed = remove(root.right, value) 73 | return root, existed 74 | } 75 | 76 | // 如果此节点正是要移除的节点,那么返回此节点,同时返回之前可能需要调整. 77 | existed = true 78 | 79 | // 如果此节点没有孩子,直接返回即可 80 | if root.left == nil && root.right == nil { 81 | root = nil 82 | return root, existed 83 | } 84 | 85 | // 如果左子节点为空, 提升右子节点 86 | if root.left == nil { 87 | root = root.right 88 | return root, existed 89 | } 90 | // 如果右子节点为空, 提升左子节点 91 | if root.right == nil { 92 | root = root.left 93 | return root, existed 94 | } 95 | 96 | // 如果左右节点都存在,那么从左边节点找到一个最小的节点提升,这个节点肯定比左子树所有节点都大. 97 | // 也可以从左子树节点中找一个最大的提升,道理一样. 98 | 99 | smallestInRight, _ := min(root.right) 100 | // 提升 101 | root.value = smallestInRight 102 | // 从右边子树中移除此节点 103 | root.right, _ = remove(root.right, smallestInRight) 104 | 105 | return root, existed 106 | } 107 | 108 | // Search 搜索元素(检查元素是否存在) 109 | func (bst *BST) Search(value int) bool { 110 | return search(bst.root, value) 111 | } 112 | 113 | // Min 二叉搜索树中的最小值 114 | func (bst *BST) Min() (int, bool) { 115 | return min(bst.root) 116 | } 117 | 118 | func min(node *Node) (int, bool) { 119 | if node == nil { 120 | return 0, false 121 | } 122 | 123 | n := node 124 | // 从左边找 125 | for { 126 | if n.left == nil { 127 | return n.value, true 128 | } 129 | n = n.left 130 | } 131 | } 132 | 133 | // Max 二叉搜索树中的最大值 134 | func (bst *BST) Max() (int, bool) { 135 | return max(bst.root) 136 | } 137 | 138 | func max(node *Node) (int, bool) { 139 | if node == nil { 140 | return 0, false 141 | } 142 | 143 | n := node 144 | // 从右边找 145 | for { 146 | if n.right == nil { 147 | return n.value, true 148 | } 149 | n = n.right 150 | } 151 | } 152 | 153 | func search(n *Node, value int) bool { 154 | if n == nil { 155 | return false 156 | } 157 | if value < n.value { 158 | return search(n.left, value) 159 | } 160 | if value > n.value { 161 | return search(n.right, value) 162 | } 163 | return true 164 | } 165 | 166 | // InOrderTraverse 中序遍历 167 | func (bst *BST) InOrderTraverse(f func(int)) { 168 | inOrderTraverse(bst.root, f) 169 | } 170 | func inOrderTraverse(n *Node, f func(int)) { 171 | if n != nil { 172 | inOrderTraverse(n.left, f) 173 | f(n.value) // 中 174 | inOrderTraverse(n.right, f) 175 | } 176 | } 177 | 178 | // PreOrderTraverse 前序遍历 179 | func (bst *BST) PreOrderTraverse(f func(int)) { 180 | preOrderTraverse(bst.root, f) 181 | } 182 | 183 | func preOrderTraverse(n *Node, f func(int)) { 184 | if n != nil { 185 | f(n.value) // 前 186 | preOrderTraverse(n.left, f) 187 | preOrderTraverse(n.right, f) 188 | } 189 | } 190 | 191 | // PostOrderTraverse 后序遍历 192 | func (bst *BST) PostOrderTraverse(f func(int)) { 193 | postOrderTraverse(bst.root, f) 194 | } 195 | 196 | func postOrderTraverse(n *Node, f func(int)) { 197 | if n != nil { 198 | postOrderTraverse(n.left, f) 199 | postOrderTraverse(n.right, f) 200 | f(n.value) // 后 201 | } 202 | } 203 | 204 | func (bst *BST) String() { 205 | fmt.Println("------------------------------------------------") 206 | stringify(bst.root, 0) 207 | fmt.Println("------------------------------------------------") 208 | } 209 | 210 | func stringify(n *Node, level int) { 211 | if n != nil { 212 | format := "" 213 | for i := 0; i < level; i++ { 214 | format += " " 215 | } 216 | format += "---[ " 217 | level++ 218 | stringify(n.left, level) 219 | fmt.Printf(format+"%d\n", n.value) 220 | stringify(n.right, level) 221 | } 222 | } 223 | --------------------------------------------------------------------------------