diff --git a/TODO.md b/TODO.md index 044090f8..9806082b 100644 --- a/TODO.md +++ b/TODO.md @@ -6,3 +6,5 @@ - [ ] 工程实现用到的算法解析 - [ ] 周赛计划 - [ ] 面试体系计划 + +https://www.ctolib.com/0xAX-go-algorithms.html \ No newline at end of file diff --git a/advanced_algorithm/backtrack.md b/advanced_algorithm/backtrack.md index bd923e61..909c7f25 100644 --- a/advanced_algorithm/backtrack.md +++ b/advanced_algorithm/backtrack.md @@ -20,6 +20,12 @@ func backtrack(选择列表,路径): 核心就是从选择列表里做一个选择,然后一直递归往下搜索答案,如果遇到路径不通,就返回来撤销这次选择。 +## 参考阅读 +[回溯算法解题套路框架](https://labuladong.gitbook.io/algo/suan-fa-si-wei-xi-lie/hui-su-suan-fa-xiang-jie-xiu-ding-ban) +[回溯算法团灭子集、排列、组合问题](https://labuladong.gitbook.io/algo/suan-fa-si-wei-xi-lie/zi-ji-pai-lie-zu-he) +[回溯算法最佳实践:解数独](https://labuladong.gitbook.io/algo/suan-fa-si-wei-xi-lie/sudoku) +[回溯算法最佳实践:括号生成](https://labuladong.gitbook.io/algo/suan-fa-si-wei-xi-lie/he-fa-kuo-hao-sheng-cheng) + ## 示例 ### [subsets](https://leetcode-cn.com/problems/subsets/) diff --git a/data_structure/binary_tree.md b/data_structure/binary_tree.md index b5c84b49..20828edc 100644 --- a/data_structure/binary_tree.md +++ b/data_structure/binary_tree.md @@ -2,6 +2,9 @@ ## 知识点 +[二叉树](https://labuladong.gitbook.io/algo/shu-ju-jie-gou-xi-lie/er-cha-shu-xi-lie-1) + + ### 二叉树遍历 **前序遍历**:**先访问根节点**,再前序遍历左子树,再前序遍历右子树 diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..28329485 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module algorithm-pattern + +go 1.13 diff --git a/src/calculate/calculate.go b/src/calculate/calculate.go new file mode 100644 index 00000000..d1aeb518 --- /dev/null +++ b/src/calculate/calculate.go @@ -0,0 +1,83 @@ +package calculate + +func calculate(s string) int { + // 遍历s, 遇到数字追加到当前tempNum + // sign 保存上一次的出现的符号,用于与当前数字进行组合,默认'+' + // stack 用来保存所有数字与操作符的组合 +4 -3 *2 +1 + // 遇到 + - 将tempNum入栈, + // 遇到 * / 将栈顶取出, 与当前数结合,再入栈 + // 将所有栈结果累加 + + sign := '+' + tempNum := 0 + stack := make([]int, 0) + + for i := 0; i < len(s); i++ { + c := s[i] + if c >= '0' && c <= '9' { + tempNum = tempNum*10 + int(c-'0') + } else { + // 遇上操作符,需要将数字入栈,同时更新操作符缓存 + switch sign { + case '+': + stack = append(stack, tempNum) + case '-': + stack = append(stack, -tempNum) + case '*': + //top := stack[len(stack)-1] + //stack[len(stack)-1] = top*tempNum + stack[len(stack)-1] *= tempNum + case '/': + stack[len(stack)-1] /= tempNum + } + + // 更新sign tempNum + sign = rune(c) + tempNum = 0 + } + } + res := 0 + for i := 0; i < len(stack); i++ { + res += stack[i] + } + return res +} + +func calculateV1(s string) int { + +} + +func calc(s string, i *int) int { + // 计算不包含括号的表达式 + + res := 0 + sign := '+' + tempNum := 0 + + for *i < len(s) { + c := s[*i] + if c >= '0' && c <= 9 { + tempNum = tempNum*10 + int(c-'0') + } + + if c == '+' || c == '-' || *i == len(s)-1 { + switch sign { + case '+': + res += tempNum + case '-': + res -= tempNum + } + sign = rune(c) + tempNum = 0 + } + + *i++ + if c == '(' { + tempNum = calc(s, i) + } + if c == ')' { + break + } + } + return res +} diff --git a/src/interview/question.go b/src/interview/question.go new file mode 100644 index 00000000..9f1bdc63 --- /dev/null +++ b/src/interview/question.go @@ -0,0 +1,114 @@ +package interview + +import ( + "context" + "fmt" + "time" +) + +func cacl(index string, a, b int) int { + ret := a + b + fmt.Println(index, a, b, ret) + return ret +} + +func DeferAction() { + a := 1 + b := 2 + + defer cacl("1", a, cacl("10", a, b)) + + b = 0 + defer cacl("2", a, cacl("20", a, b)) + b = 3 + + panic("exit") + + // output + // 10 1 2 3 + // 20 1 0 1 + // 2 1 1 2 + // 1 1 3 4 + // panic: exit +} + +func CloseChan() { + type A struct { + val int + } + + c := make(chan *A, 10) + + c <- &A{val: 1} + c <- &A{val: 2} + close(c) + + for i := range c { + fmt.Println(i) + } + + fmt.Println(<-c) + fmt.Println(<-c) + + // output + + //&{1} + //&{2} + // + // +} + +func MapInit() { + type A struct { + val int + } + + // 以下用法错误 map的值是无法取址的,也就无法对结构体里的field进行操作; 因为map是无序的,并且随时存在扩容缩容,其地址也就不固定 + // m := map[string]A{"x": {1}} + // m["x"].val = 2 + + // 解决方案 + // m := map[string]&A +} + +func ConText() { + ctx, _ := context.WithCancel(context.Background()) + //defer cancel() + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + + resp := make(chan int, 3) + err := make(chan interface{}, 3) + + operation := func(pid int, ctx context.Context, dst int, resp chan int, err chan interface{}) { + n := 1 + for { + select { + case <-ctx.Done(): + fmt.Println(pid, "canceled", ctx.Err()) + err <- ctx.Err() + return + case <-time.After(time.Second): + fmt.Println(pid, "1 second pass", n) + n++ + if n == dst { + resp <- pid + return + } + } + } + } + + go operation(1, ctx, 10, resp, err) + go operation(2, ctx, 10, resp, err) + go operation(3, ctx, 7, resp, err) + + select { + case pid := <-resp: + fmt.Println(pid, "find dst and cancel other goroutines") + case e := <-err: + fmt.Println(e) + } + + cancel() + time.Sleep(1 * time.Second) // wait for goroutines return +} diff --git a/src/interview/question_test.go b/src/interview/question_test.go new file mode 100644 index 00000000..cb2fefdc --- /dev/null +++ b/src/interview/question_test.go @@ -0,0 +1,15 @@ +package interview + +import "testing" + +func TestDeferAction(t *testing.T) { + DeferAction() +} + +func TestCloseChan(t *testing.T) { + CloseChan() +} + +func TestConText(t *testing.T) { + ConText() +} diff --git a/src/linkedlist/list.go b/src/linkedlist/list.go new file mode 100644 index 00000000..cc4bbacf --- /dev/null +++ b/src/linkedlist/list.go @@ -0,0 +1,184 @@ +package linkedlist + +import ( + "fmt" +) + +type ListNode struct { + val interface{} + pre *ListNode + next *ListNode +} + +func NewIntList(nums []int) *ListNode { + if len(nums) == 0 { + return nil + } + dummy := &ListNode{} + head := dummy + for _, val := range nums { + node := &ListNode{ + val: val, + } + node.pre = head + head.next = node + head = node + } + + return dummy.next +} + +func (head *ListNode) Print() { + curr := head + for curr != nil { + fmt.Printf("%v->", curr.val) + curr = curr.next + } + println("NULL") +} + +func (head *ListNode) String() string { + s := "" + curr := head + for curr != nil { + s += fmt.Sprintf("%v->", curr.val) + curr = curr.next + } + return s + "NULL" +} + +// 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 +func DeleteDuplicates(head *ListNode) *ListNode { + current := head + for current != nil { + for current.next != nil && current.next.val == current.val { + current.next = current.next.next + } + current = current.next + } + + return head +} + +// 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中   没有重复出现的数字。 +// 只出现一次的节点 +func DeleteDupKeepOnce(head *ListNode) *ListNode { + dummy := &ListNode{} + dummy.next = head + current := dummy + + var rmVal interface{} + for current.next != nil && current.next.next != nil { + if current.next.val == current.next.next.val { + rmVal = current.next.val + // 指针直接跳到第三个节点 + current.next = current.next.next.next + // 顺序删除 + for current.next != nil && current.next.val == rmVal { + current.next = current.next.next + } + } else { + current = current.next + } + } + + return dummy.next +} + +// 反转一个单链表。 +// 思路:用一个 prev 节点保存向前指针,temp 保存向后的临时指针 +func ReverseList(head *ListNode) *ListNode { + var pre *ListNode + for head != nil { + temp := head.next + head.next = pre + pre = head + head = temp + } + + return pre +} + +// 反转从位置  *m*  到  *n*  的链表。请使用一趟扫描完成反转。 +func ReverseListMN(head *ListNode, m, n int) *ListNode { + if m < 0 || m > n { + return head + } + + dummy := &ListNode{} + dummy.next = head + + i := 0 + current := dummy + // 遍历跳过 + nodeMPre := current + for current != nil && i < m { + nodeMPre = current + current = current.next + i++ + } + + // 遍历 + var pre *ListNode + nodeM := current + for current != nil && i <= n { + temp := current.next + current.next = pre + pre = current + current = temp + i++ + } + + nodeMPre.next = pre + nodeM.next = current + + return dummy.next +} + +// 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于  *x*  的节点都在大于或等于  *x*  的节点之前。 +// 思路:将大于 x 的节点,放到另外一个链表,最后连接这两个链表, 无需排序 +func PartitionX(head *ListNode, x int) *ListNode { + headDummy := &ListNode{} + tailDummy := &ListNode{} + + headDummy.next = head + current := headDummy + tail := tailDummy + for current.next != nil { + if current.next.val.(int) < x { + current = current.next + } else { + tail.next = current.next + tail = tail.next + current.next = current.next.next + } + } + + tail.next = nil + current.next = tailDummy.next + + return headDummy.next +} + +func Xxx() { + type A struct { + x int + y int + z []int + } + a := &A{ + x: 0, + y: 1, + z: make([]int, 0), + } + a.z = append(a.z, 1) + + fmt.Printf("a.ptr:%p a.x:%d a.y:%d, a.z:%v \n", a, a.x, a.y, a.z) + + c := a + a.x = 10 + a.y = 11 + c.z = append(c.z, 10) + fmt.Printf("c.ptr:%p c.x:%d c.y:%d, c.z:%v \n", c, c.x, c.y, c.z) + fmt.Printf("a.ptr:%p a.x:%d a.y:%d, a.z:%v \n", a, a.x, a.y, a.z) +} diff --git a/src/linkedlist/list_test.go b/src/linkedlist/list_test.go new file mode 100644 index 00000000..d9e5f996 --- /dev/null +++ b/src/linkedlist/list_test.go @@ -0,0 +1,49 @@ +package linkedlist + +import "testing" + +func defaultSortedList() *ListNode { + return NewIntList([]int{1, 2, 2, 2, 2, 3, 3, 4, 5, 5}) +} + +func TestNewIntList(t *testing.T) { + list := defaultSortedList() + list.Print() + println(list.String()) +} + +func TestDeleteDuplicates(t *testing.T) { + head := defaultSortedList() + head.Print() + DeleteDuplicates(head) + head.Print() +} + +func TestDeleteDupKeepOnce(t *testing.T) { + head := defaultSortedList() + head.Print() + DeleteDupKeepOnce(head) + head.Print() +} + +func TestReverseList(t *testing.T) { + head := defaultSortedList() + head.Print() + ReverseList(head).Print() +} + +func TestReverseListMN(t *testing.T) { + head := NewIntList([]int{1, 2, 3, 4, 5}) + head.Print() + ReverseListMN(head, 1, 3).Print() +} + +func TestPartitionX(t *testing.T) { + head := NewIntList([]int{5, 4, 3, 1, 2}) + head.Print() + PartitionX(head, 3).Print() +} + +func TestXxx(t *testing.T) { + Xxx() +} diff --git a/src/nums/backtrack.go b/src/nums/backtrack.go new file mode 100644 index 00000000..47253ce0 --- /dev/null +++ b/src/nums/backtrack.go @@ -0,0 +1,225 @@ +package nums + +import ( + "sort" + "strings" +) + +// 递归解法 +func SubSets(nums []int) [][]int { + if len(nums) == 0 { + return [][]int{{}} + } + + cur := nums[len(nums)-1] + res := SubSets(nums[:len(nums)-1]) + l := len(res) + for i := 0; i < l; i++ { + res = append(res, append(res[i], cur)) + } + return res +} + +// 回溯解法 +func SubSetsV2(nums []int) [][]int { + var ( + backtrack func(nums []int, track []int, res *[][]int) + + res = make([][]int, 0) + track = make([]int, 0) + ) + + backtrack = func(nums []int, track []int, res *[][]int) { + tmp := make([]int, len(track)) + copy(tmp, track) + *res = append(*res, tmp) + + for i := 0; i < len(nums); i++ { + track = append(track, nums[i]) + backtrack(nums[i+1:], track, res) + track = track[:len(track)-1] + } + } + + backtrack(nums, track, &res) + + return res +} + +// 回溯法 有重复数字的序列 +func SubsetsDup(nums []int) [][]int { + var ( + backtrack func(nums []int, track []int, res *[][]int) + + res = make([][]int, 0) + track = make([]int, 0) + ) + + backtrack = func(nums []int, track []int, res *[][]int) { + tmp := make([]int, len(track)) + copy(tmp, track) + *res = append(*res, tmp) + + for i := 0; i < len(nums); i++ { + // 去重 同一树层去重 + if i > 0 && nums[i] == nums[i-1] { + continue + } + + track = append(track, nums[i]) + backtrack(nums[i+1:], track, res) + track = track[:len(track)-1] + } + } + + sort.Ints(nums) + backtrack(nums, track, &res) + + return res +} + +// 回溯法 组合问题 +func Combine(n, k int) [][]int { + var ( + backtrack func(n, pos, k int, track []int, res *[][]int) + + res = make([][]int, 0) + track = make([]int, 0) + ) + + backtrack = func(n, pos, k int, track []int, res *[][]int) { + if len(track) == k { + ans := make([]int, k) + copy(ans, track) + *res = append(*res, ans) + return + } + + for i := pos; i <= n; i++ { + track = append(track, i) + backtrack(n, i+1, k, track, res) + track = track[:len(track)-1] + } + } + + backtrack(n, 1, k, track, &res) + + return res +} + +// 非重复序列 +func Permutation(nums []int) [][]int { + var ( + backtrack func(nums []int, visited []bool, track []int, res *[][]int) + + res = make([][]int, 0) + visited = make([]bool, len(nums)) + track = make([]int, 0) + ) + + backtrack = func(nums []int, visited []bool, track []int, res *[][]int) { + if len(track) == len(nums) { + ans := make([]int, len(nums)) + copy(ans, track) + *res = append(*res, ans) + return + } + + for i := 0; i < len(nums); i++ { + if visited[i] { + continue + } + visited[i] = true + track = append(track, nums[i]) + backtrack(nums, visited, track, res) + track = track[:len(track)-1] + visited[i] = false + } + } + + backtrack(nums, visited, track, &res) + + return res +} + +// 有重复数字的序列 +func PermutationV2(nums []int) [][]int { + var ( + backtrack func(nums []int, visited []bool, track []int, res *[][]int) + + res = make([][]int, 0) + visited = make([]bool, len(nums)) + track = make([]int, 0) + ) + + backtrack = func(nums []int, visited []bool, track []int, res *[][]int) { + if len(track) == len(nums) { + ans := make([]int, len(nums)) + copy(ans, track) + *res = append(*res, ans) + return + } + + for i := 0; i < len(nums); i++ { + if visited[i] { + continue + } + + // 去重 同一树层去重 visited[i-1] == false + if i > 0 && nums[i] == nums[i-1] && !visited[i-1] { + continue + } + + //// 去重 同一树枝去重 visited[i-1] == false + //if i >0 && nums[i] == nums[i-1] && visited[i-1] { + // continue + //} + + visited[i] = true + track = append(track, nums[i]) + backtrack(nums, visited, track, res) + track = track[:len(track)-1] + visited[i] = false + } + } + + sort.Ints(nums) + backtrack(nums, visited, track, &res) + + return res +} + +func RestoreIpAddresses(s string) []string { + var ( + res = make([]string, 0) + track = make([]string, 0) + ) + backtrack(s, len(s), 0, 0, track, &res) + return res +} + +func backtrack(s string, total, lastIndex int, segLen int, track []string, res *[]string) { + + // 每段ip最多3位, + if total-lastIndex-segLen > (4-len(track))*3 || total-lastIndex-segLen < 4-len(track) { + return + } + + if len(track) == 4 { + ts := "" + for i := 0; i < len(track); i++ { + ts += track[i] + "." + } + *res = append(*res, strings.TrimSuffix(ts, ".")) + return + } + + for i := 1; i <= 3; i++ { + if s[lastIndex:lastIndex+i] > "255" || (i > 1 && s[lastIndex] == '0') { + continue + } + track = append(track, s[lastIndex:lastIndex+i]) + backtrack(s, len(s), lastIndex+i, i, track, res) + track = track[:len(track)-1] + } +} diff --git a/src/nums/backtrack_test.go b/src/nums/backtrack_test.go new file mode 100644 index 00000000..753742cb --- /dev/null +++ b/src/nums/backtrack_test.go @@ -0,0 +1,25 @@ +package nums + +import ( + "fmt" + "testing" +) + +func TestSubSets(t *testing.T) { + fmt.Println(SubSets([]int{1, 2, 3})) + fmt.Println(SubSetsV2([]int{1, 2, 3})) + fmt.Println(SubsetsDup([]int{1, 2, 2})) +} + +func TestCombine(t *testing.T) { + fmt.Println(Combine(4, 2)) +} + +func TestPermutation(t *testing.T) { + fmt.Println(Permutation([]int{1, 2, 3})) + fmt.Println(PermutationV2([]int{1, 2, 2})) +} + +func TestRestoreIpAddresses(t *testing.T) { + fmt.Println(RestoreIpAddresses("25525511135")) +} diff --git a/src/sort/quick_sort.go b/src/sort/quick_sort.go new file mode 100644 index 00000000..38b883ca --- /dev/null +++ b/src/sort/quick_sort.go @@ -0,0 +1,58 @@ +package sort + +func Quicksort(nums []int, start, end int) { + if start >= end { + return + } + p := partition(nums, start, end) + Quicksort(nums, start, p-1) + Quicksort(nums, p+1, end) +} + +func partition(nums []int, start, end int) int { + base := nums[end] + i := start + for j := start; j < end; j++ { + if nums[j] < base { + nums[i], nums[j] = nums[j], nums[i] + i++ + } + } + nums[i], nums[end] = nums[end], nums[i] + return i +} + +func Mergesort(nums []int) []int { + if len(nums) <= 1 { + return nums + } + + mid := len(nums) / 2 + left := Mergesort(nums[:mid]) + right := Mergesort(nums[mid:]) + + return merge(left, right) +} + +func merge(nums1, nums2 []int) []int { + res := make([]int, 0) + i, j := 0, 0 + for i < len(nums1) && j < len(nums2) { + if nums1[i] <= nums2[j] { + res = append(res, nums1[i]) + i++ + } else { + res = append(res, nums2[j]) + j++ + } + } + + if i < len(nums1) { + res = append(res, nums1[i:]...) + } + if j < len(nums2) { + res = append(res, nums2[j:]...) + } + + return res +} diff --git a/src/sort/quick_sort_test.go b/src/sort/quick_sort_test.go new file mode 100644 index 00000000..7af17de6 --- /dev/null +++ b/src/sort/quick_sort_test.go @@ -0,0 +1,18 @@ +package sort + +import ( + "fmt" + "testing" +) + +func TestQuicksort(t *testing.T) { + nums := []int{1, 3, 2, 5, 6, 4} + Quicksort(nums, 0, len(nums)-1) + fmt.Println(nums) +} + +func TestMergesort(t *testing.T) { + nums := []int{1, 3, 2, 5, 6, 4} + res := Mergesort(nums) + fmt.Println(res) +} diff --git a/src/str/str.go b/src/str/str.go new file mode 100644 index 00000000..17211459 --- /dev/null +++ b/src/str/str.go @@ -0,0 +1,91 @@ +package str + +import ( + "fmt" + "strings" +) + +// O(m*n) +func Contain(haystack string, needle string) int { + if len(needle) == 0 { + return 0 + } + var i, j int + for i = 0; i < len(haystack)-len(needle)+1; i++ { + for ; j < len(needle); j++ { + if haystack[i+j] != needle[j] { + break + } + } + if j == len(needle) { + return i + } + } + pause + return -1 +} + +// 判断s 是否是t 的子序列;可由t删减若干字符得到,但相对顺序不变 +// ace abcde true +// cae abcde false +func SubStr(s, t string) bool { + curIndex := 0 + i := 0 + for ; i < len(s); i++ { + println("before", i, curIndex) + println(s[i : i+1]) + println(t[curIndex:]) + tmp := strings.Index(t[curIndex:], s[i:i+1]) + println("tmp", tmp) + + if tmp < 0 { + break + } + curIndex += 1 + tmp + println("after", i, curIndex) + } + + if i == len(s) { + return true + } + return false +} + +func Permute(nums []int) [][]int { + result := make([][]int, 0) + list := make([]int, 0) + // 标记这个元素是否已经添加到结果集 + visited := make([]bool, len(nums)) + backtrack(nums, visited, list, &result) + return result +} + +// nums 输入集合 +// visited 当前递归标记过的元素 +// list 临时结果集(路径) +// result 最终结果 +func backtrack(nums []int, visited []bool, list []int, result *[][]int) { + // 返回条件:临时结果和输入集合长度一致 才是全排列 + if len(list) == len(nums) { + ans := make([]int, len(list)) + copy(ans, list) + *result = append(*result, ans) + return + } + for i := 0; i < len(nums); i++ { + // 已经添加过的元素,直接跳过 + if visited[i] { + continue + } + // 添加元素 + list = append(list, nums[i]) + visited[i] = true + backtrack(nums, visited, list, result) + // 移除元素 + visited[i] = false + + println("after loop index", i) + fmt.Println(list) + list = list[0 : len(list)-1] + } +} diff --git a/src/str/str_test.go b/src/str/str_test.go new file mode 100644 index 00000000..125b1107 --- /dev/null +++ b/src/str/str_test.go @@ -0,0 +1,22 @@ +package str + +import ( + "fmt" + "testing" +) + +func TestContain(t *testing.T) { + str := "abcdeqqqqqwww" + needle := "www" + println(Contain(str, needle)) +} + +func TestSubStr(t *testing.T) { + s := "ccae" + ss := "abcdeeeca" + println(SubStr(s, ss)) +} + +func TestPermute(t *testing.T) { + fmt.Println(Permute([]int{1, 2, 3})) +} diff --git a/src/tree/tree.go b/src/tree/tree.go new file mode 100644 index 00000000..ff2ed83f --- /dev/null +++ b/src/tree/tree.go @@ -0,0 +1,222 @@ +package tree + +import ( + "fmt" +) + +const ( + NULL = -1 +) + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +// Traversal +func PreTraversal(root *TreeNode) { + if root == nil { + fmt.Printf("%d,", NULL) + return + } + fmt.Printf("%d,", root.Val) + PreTraversal(root.Left) + PreTraversal(root.Right) +} + +func MidTraversal(root *TreeNode) { + if root == nil { + fmt.Printf("%d,", NULL) + return + } + PreTraversal(root.Left) + fmt.Printf("%d,", root.Val) + PreTraversal(root.Right) +} + +// 思路:通过stack 保存已经访问的元素,用于原路返回 +func InorderTraversal(root *TreeNode) []int { + result := make([]int, 0) + if root == nil { + return result + } + stack := make([]*TreeNode, 0) + for len(stack) > 0 || root != nil { + for root != nil { + stack = append(stack, root) + root = root.Left // 一直向左 + } + // 弹出 + val := stack[len(stack)-1] + stack = stack[:len(stack)-1] + result = append(result, val.Val) + root = val.Right + } + return result +} + +func PostOrderTraversal(root *TreeNode) { + if root == nil { + fmt.Printf("%d,", NULL) + return + } + PreTraversal(root.Left) + + PreTraversal(root.Right) + + fmt.Printf("%d,", root.Val) +} + +func PreOderDeserialize(data []int) *TreeNode { + var deserialize func(data []int, index *int) *TreeNode + + deserialize = func(data []int, index *int) *TreeNode { + if *index >= len(data) { + return nil + } + + val := data[*index] + *index++ + if val == NULL { + return nil + } + + root := &TreeNode{Val: val} + root.Left = deserialize(data, index) + root.Right = deserialize(data, index) + + return root + } + + index := 0 + return deserialize(data, &index) +} + +// 后序遍历 反序列化, 最后一位是root +func PostOderDeserialize(data []int) *TreeNode { + var deserialize func(data []int, index *int) *TreeNode + + deserialize = func(data []int, index *int) *TreeNode { + if *index < 0 { + return nil + } + + val := data[*index] + *index-- + if val == NULL { + return nil + } + + root := &TreeNode{Val: val} + root.Left = deserialize(data, index) + root.Right = deserialize(data, index) + + return root + } + + index := len(data) - 1 + return deserialize(data, &index) +} + +func (root *TreeNode) PreOrderSerialize() []int { + var ( + traversal func(node *TreeNode, res *[]int) + res = make([]int, 0) + ) + + traversal = func(node *TreeNode, res *[]int) { + if node == nil { + *res = append(*res, NULL) + return + } + + *res = append(*res, node.Val) + traversal(node.Left, res) + traversal(node.Right, res) + } + + traversal(root, &res) + + return res +} + +func (root *TreeNode) PostOrderSerialize() []int { + var ( + traversal func(node *TreeNode, res *[]int) + res = make([]int, 0) + ) + + traversal = func(node *TreeNode, res *[]int) { + if node == nil { + *res = append(*res, NULL) + return + } + + traversal(node.Left, res) + traversal(node.Right, res) + *res = append(*res, node.Val) + } + + traversal(root, &res) + + return res +} + +func MaxDepth(root *TreeNode) int { + var ( + queue = make([]*TreeNode, 0) + depth = 0 + ) + + queue = append(queue, root) + for len(queue) > 0 { + cur := queue[0] + queue = queue[1:] + + // 判断target, 此题全部遍历完即可 + fmt.Print(cur.Val, ",") + + // 将所有相邻节点加入队列 + if cur.Left != nil { + queue = append(queue, cur.Left) + } + if cur.Right != nil { + queue = append(queue, cur.Right) + } + + // step +1 + depth++ + } + + return depth +} + +func PathSum(root *TreeNode, sum int) [][]int { + var ( + res = make([][]int, 0) + path = make([]int, 0) + ) + + traversal(root, sum, path, &res) + return res +} + +func traversal(root *TreeNode, sum int, list []int, res *[][]int) { + if root == nil { + return + } + list = append(list, root.Val) + fmt.Println(list) + fmt.Println(sum) + if root.Left == nil && root.Right == nil { + if sum == root.Val { + *res = append(*res, list) + } + return + } + + traversal(root.Left, sum-root.Val, list, res) + + traversal(root.Right, sum-root.Val, list, res) +} diff --git a/src/tree/tree_test.go b/src/tree/tree_test.go new file mode 100644 index 00000000..3dd5f862 --- /dev/null +++ b/src/tree/tree_test.go @@ -0,0 +1,51 @@ +package tree + +import ( + "fmt" + "math" + "testing" +) + +func TestDeserialize(t *testing.T) { + root := PreOderDeserialize([]int{1, 2, -1, 4, -1, -1, 3, -1, -1}) + PreTraversal(root) + println() + fmt.Println(root.PreOrderSerialize()) + fmt.Println(root.PostOrderSerialize()) +} + +func TestTreeNode_Serialize(t *testing.T) { + root := &TreeNode{Val: 1} + root.Left = &TreeNode{Val: 2} + root.Right = &TreeNode{Val: 3} + + root.Left.Right = &TreeNode{Val: 4} + + PreTraversal(root) + println() + fmt.Println(root.PreOrderSerialize()) + fmt.Println(root.PostOrderSerialize()) +} + +func TestMidTraversal(t *testing.T) { + root := PreOderDeserialize([]int{1, 2, -1, 4, -1, -1, 3, -1, -1}) + MidTraversal(root) + fmt.Println(InorderTraversal(root)) +} + +func TestMaxDepth(t *testing.T) { + root := PreOderDeserialize([]int{1, 2, -1, 4, -1, -1, 3, -1, -1}) + MaxDepth(root) +} + +// 1 +//2 3 +// 4 + +func TestPathSum(t *testing.T) { + root := PreOderDeserialize([]int{5, 4, 11, 7, -1, -1, 2, -1, -1, 8, 13, -1, -1, 4, 5, -1, -1, 1, -1, -1}) + PreTraversal(root) + rs := PathSum(root, 22) + fmt.Println(rs) + math.Abs() +}