mirror of
https://github.com/halfrost/LeetCode-Go.git
synced 2025-07-05 08:27:30 +08:00
添加 structures
This commit is contained in:
30
structures/Heap.go
Normal file
30
structures/Heap.go
Normal file
@ -0,0 +1,30 @@
|
||||
package structures
|
||||
|
||||
// intHeap 实现了 heap 的接口
|
||||
type intHeap []int
|
||||
|
||||
func (h intHeap) Len() int {
|
||||
return len(h)
|
||||
}
|
||||
|
||||
func (h intHeap) Less(i, j int) bool {
|
||||
return h[i] < h[j]
|
||||
}
|
||||
|
||||
func (h intHeap) Swap(i, j int) {
|
||||
h[i], h[j] = h[j], h[i]
|
||||
}
|
||||
|
||||
func (h *intHeap) Push(x interface{}) {
|
||||
// Push 使用 *h,是因为
|
||||
// Push 增加了 h 的长度
|
||||
*h = append(*h, x.(int))
|
||||
}
|
||||
|
||||
func (h *intHeap) Pop() interface{} {
|
||||
// Pop 使用 *h ,是因为
|
||||
// Pop 减短了 h 的长度
|
||||
res := (*h)[len(*h)-1]
|
||||
*h = (*h)[:len(*h)-1]
|
||||
return res
|
||||
}
|
30
structures/Heap_test.go
Normal file
30
structures/Heap_test.go
Normal file
@ -0,0 +1,30 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_intHeap(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
ih := new(intHeap)
|
||||
heap.Init(ih)
|
||||
|
||||
heap.Push(ih, 1)
|
||||
heap.Pop(ih)
|
||||
|
||||
begin, end := 0, 10
|
||||
for i := begin; i < end; i++ {
|
||||
heap.Push(ih, i)
|
||||
ast.Equal(0, (*ih)[0], "插入 %d 后的最小值却是 %d,ih=%v", i, (*ih)[0], (*ih))
|
||||
}
|
||||
|
||||
for i := begin; i < end; i++ {
|
||||
fmt.Println(i, *ih)
|
||||
ast.Equal(i, heap.Pop(ih), "Pop 后 ih=%v", (*ih))
|
||||
}
|
||||
}
|
30
structures/Interval.go
Normal file
30
structures/Interval.go
Normal file
@ -0,0 +1,30 @@
|
||||
package structures
|
||||
|
||||
// Interval 提供区间表示
|
||||
type Interval struct {
|
||||
Start int
|
||||
End int
|
||||
}
|
||||
|
||||
// Interval2Ints 把 Interval 转换成 整型切片
|
||||
func Interval2Ints(i Interval) []int {
|
||||
return []int{i.Start, i.End}
|
||||
}
|
||||
|
||||
// IntervalSlice2Intss 把 []Interval 转换成 [][]int
|
||||
func IntervalSlice2Intss(is []Interval) [][]int {
|
||||
res := make([][]int, 0, len(is))
|
||||
for i := range is {
|
||||
res = append(res, Interval2Ints(is[i]))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Intss2IntervalSlice 把 [][]int 转换成 []Interval
|
||||
func Intss2IntervalSlice(intss [][]int) []Interval {
|
||||
res := make([]Interval, 0, len(intss))
|
||||
for _, ints := range intss {
|
||||
res = append(res, Interval{Start: ints[0], End: ints[1]})
|
||||
}
|
||||
return res
|
||||
}
|
59
structures/Interval_test.go
Normal file
59
structures/Interval_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Interval2Ints(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
actual := Interval2Ints(Interval{Start: 1, End: 2})
|
||||
expected := []int{1, 2}
|
||||
ast.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func Test_IntervalSlice2Intss(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
actual := IntervalSlice2Intss(
|
||||
[]Interval{
|
||||
Interval{
|
||||
Start: 1,
|
||||
End: 2,
|
||||
},
|
||||
Interval{
|
||||
Start: 3,
|
||||
End: 4,
|
||||
},
|
||||
},
|
||||
)
|
||||
expected := [][]int{
|
||||
[]int{1, 2},
|
||||
[]int{3, 4},
|
||||
}
|
||||
|
||||
ast.Equal(expected, actual)
|
||||
}
|
||||
func Test_Intss2IntervalSlice(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
expected := []Interval{
|
||||
Interval{
|
||||
Start: 1,
|
||||
End: 2,
|
||||
},
|
||||
Interval{
|
||||
Start: 3,
|
||||
End: 4,
|
||||
},
|
||||
}
|
||||
actual := Intss2IntervalSlice([][]int{
|
||||
[]int{1, 2},
|
||||
[]int{3, 4},
|
||||
},
|
||||
)
|
||||
|
||||
ast.Equal(expected, actual)
|
||||
}
|
78
structures/ListNode.go
Normal file
78
structures/ListNode.go
Normal file
@ -0,0 +1,78 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ListNode 是链接节点
|
||||
// 这个不能复制到*_test.go文件中。会导致Travis失败
|
||||
type ListNode struct {
|
||||
Val int
|
||||
Next *ListNode
|
||||
}
|
||||
|
||||
// List2Ints convert List to []int
|
||||
func List2Ints(head *ListNode) []int {
|
||||
// 链条深度限制,链条深度超出此限制,会 panic
|
||||
limit := 100
|
||||
|
||||
times := 0
|
||||
|
||||
res := []int{}
|
||||
for head != nil {
|
||||
times++
|
||||
if times > limit {
|
||||
msg := fmt.Sprintf("链条深度超过%d,可能出现环状链条。请检查错误,或者放宽 l2s 函数中 limit 的限制。", limit)
|
||||
panic(msg)
|
||||
}
|
||||
|
||||
res = append(res, head.Val)
|
||||
head = head.Next
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Ints2List convert []int to List
|
||||
func Ints2List(nums []int) *ListNode {
|
||||
l := &ListNode{}
|
||||
t := l
|
||||
for _, v := range nums {
|
||||
t.Next = &ListNode{Val: v}
|
||||
t = t.Next
|
||||
}
|
||||
return l.Next
|
||||
}
|
||||
|
||||
// GetNodeWith returns the first node with val
|
||||
func (l *ListNode) GetNodeWith(val int) *ListNode {
|
||||
res := l
|
||||
for res != nil {
|
||||
if res.Val == val {
|
||||
break
|
||||
}
|
||||
res = res.Next
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Ints2ListWithCycle returns a list whose tail point to pos-indexed node
|
||||
// head's index is 0
|
||||
// if pos = -1, no cycle
|
||||
func Ints2ListWithCycle(nums []int, pos int) *ListNode {
|
||||
head := Ints2List(nums)
|
||||
if pos == -1 {
|
||||
return head
|
||||
}
|
||||
c := head
|
||||
for pos > 0 {
|
||||
c = c.Next
|
||||
pos--
|
||||
}
|
||||
tail := c
|
||||
for tail.Next != nil {
|
||||
tail = tail.Next
|
||||
}
|
||||
tail.Next = c
|
||||
return head
|
||||
}
|
68
structures/ListNode_test.go
Normal file
68
structures/ListNode_test.go
Normal file
@ -0,0 +1,68 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_l2s(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
ast.Equal([]int{}, List2Ints(nil), "输入nil,没有返回[]int{}")
|
||||
|
||||
one2three := &ListNode{
|
||||
Val: 1,
|
||||
Next: &ListNode{
|
||||
Val: 2,
|
||||
Next: &ListNode{
|
||||
Val: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
ast.Equal([]int{1, 2, 3}, List2Ints(one2three), "没有成功地转换成[]int")
|
||||
|
||||
limit := 100
|
||||
overLimitList := Ints2List(make([]int, limit+1))
|
||||
ast.Panics(func() { List2Ints(overLimitList) }, "转换深度超过 %d 限制的链条,没有 panic", limit)
|
||||
}
|
||||
|
||||
func Test_s2l(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
ast.Nil(Ints2List([]int{}), "输入[]int{},没有返回nil")
|
||||
|
||||
ln := Ints2List([]int{1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
i := 1
|
||||
for ln != nil {
|
||||
ast.Equal(i, ln.Val, "对应的值不对")
|
||||
ln = ln.Next
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getNodeWith(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
//
|
||||
ln := Ints2List([]int{1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
val := 10
|
||||
node := &ListNode{
|
||||
Val: val,
|
||||
}
|
||||
tail := ln
|
||||
for tail.Next != nil {
|
||||
tail = tail.Next
|
||||
}
|
||||
tail.Next = node
|
||||
expected := node
|
||||
actual := ln.GetNodeWith(val)
|
||||
ast.Equal(expected, actual)
|
||||
}
|
||||
|
||||
func Test_Ints2ListWithCycle(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
ints := []int{1, 2, 3}
|
||||
l := Ints2ListWithCycle(ints, -1)
|
||||
ast.Equal(ints, List2Ints(l))
|
||||
|
||||
l = Ints2ListWithCycle(ints, 1)
|
||||
ast.Panics(func() { List2Ints(l) })
|
||||
}
|
37
structures/NestedInteger.go
Normal file
37
structures/NestedInteger.go
Normal file
@ -0,0 +1,37 @@
|
||||
package structures
|
||||
|
||||
// NestedInteger is the interface that allows for creating nested lists.
|
||||
// You should not implement it, or speculate about its implementation
|
||||
type NestedInteger struct {
|
||||
Num int
|
||||
Ns []*NestedInteger
|
||||
}
|
||||
|
||||
// IsInteger Return true if this NestedInteger holds a single integer, rather than a nested list.
|
||||
func (n NestedInteger) IsInteger() bool {
|
||||
return n.Ns == nil
|
||||
}
|
||||
|
||||
// GetInteger Return the single integer that this NestedInteger holds, if it holds a single integer
|
||||
// The result is undefined if this NestedInteger holds a nested list
|
||||
// So before calling this method, you should have a check
|
||||
func (n NestedInteger) GetInteger() int {
|
||||
return n.Num
|
||||
}
|
||||
|
||||
// SetInteger Set this NestedInteger to hold a single integer.
|
||||
func (n *NestedInteger) SetInteger(value int) {
|
||||
n.Num = value
|
||||
}
|
||||
|
||||
// Add Set this NestedInteger to hold a nested list and adds a nested integer to it.
|
||||
func (n *NestedInteger) Add(elem NestedInteger) {
|
||||
n.Ns = append(n.Ns, &elem)
|
||||
}
|
||||
|
||||
// GetList Return the nested list that this NestedInteger holds, if it holds a nested list
|
||||
// The list length is zero if this NestedInteger holds a single integer
|
||||
// You can access NestedInteger's List element directly if you want to modify it
|
||||
func (n NestedInteger) GetList() []*NestedInteger {
|
||||
return n.Ns
|
||||
}
|
30
structures/NestedInterger_test.go
Normal file
30
structures/NestedInterger_test.go
Normal file
@ -0,0 +1,30 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_NestedInteger(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
n := NestedInteger{}
|
||||
|
||||
ast.True(n.IsInteger())
|
||||
|
||||
n.SetInteger(1)
|
||||
ast.Equal(1, n.GetInteger())
|
||||
|
||||
elem := NestedInteger{Num: 1}
|
||||
|
||||
expected := NestedInteger{
|
||||
Num: 1,
|
||||
Ns: []*NestedInteger{&elem},
|
||||
}
|
||||
n.Add(elem)
|
||||
|
||||
ast.Equal(expected, n)
|
||||
|
||||
ast.Equal(expected.Ns, n.GetList())
|
||||
}
|
27
structures/Point.go
Normal file
27
structures/Point.go
Normal file
@ -0,0 +1,27 @@
|
||||
package structures
|
||||
|
||||
// Point 定义了一个二维坐标点
|
||||
type Point struct {
|
||||
X, Y int
|
||||
}
|
||||
|
||||
// Intss2Points 把 [][]int 转换成 []Point
|
||||
func Intss2Points(points [][]int) []Point {
|
||||
res := make([]Point, len(points))
|
||||
for i, p := range points {
|
||||
res[i] = Point{
|
||||
X: p[0],
|
||||
Y: p[1],
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Points2Intss 把 []Point 转换成 [][]int
|
||||
func Points2Intss(points []Point) [][]int {
|
||||
res := make([][]int, len(points))
|
||||
for i, p := range points {
|
||||
res[i] = []int{p.X, p.Y}
|
||||
}
|
||||
return res
|
||||
}
|
78
structures/Point_test.go
Normal file
78
structures/Point_test.go
Normal file
@ -0,0 +1,78 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Intss2Points(t *testing.T) {
|
||||
type args struct {
|
||||
points [][]int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []Point
|
||||
}{
|
||||
{
|
||||
"测试 [][]int 转换成 []Point ",
|
||||
args{
|
||||
[][]int{
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{5, 0},
|
||||
},
|
||||
},
|
||||
[]Point{
|
||||
Point{X: 1, Y: 0},
|
||||
Point{X: 2, Y: 0},
|
||||
Point{X: 3, Y: 0},
|
||||
Point{X: 4, Y: 0},
|
||||
Point{X: 5, Y: 0},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if got := Intss2Points(tt.args.points); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("%q. intss2Points() = %v, want %v", tt.name, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Points2Intss(t *testing.T) {
|
||||
type args struct {
|
||||
points []Point
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want [][]int
|
||||
}{
|
||||
{
|
||||
"测试 [][]int 转换成 []Point ",
|
||||
args{
|
||||
[]Point{
|
||||
Point{X: 1, Y: 0},
|
||||
Point{X: 2, Y: 0},
|
||||
Point{X: 3, Y: 0},
|
||||
Point{X: 4, Y: 0},
|
||||
Point{X: 5, Y: 0},
|
||||
},
|
||||
},
|
||||
[][]int{
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
{4, 0},
|
||||
{5, 0},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if got := Points2Intss(tt.args.points); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("%q. Points2Intss() = %v, want %v", tt.name, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
54
structures/PriorityQueue.go
Normal file
54
structures/PriorityQueue.go
Normal file
@ -0,0 +1,54 @@
|
||||
package structures
|
||||
|
||||
// This example demonstrates a priority queue built using the heap interface.
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
)
|
||||
|
||||
// entry 是 priorityQueue 中的元素
|
||||
type entry struct {
|
||||
key string
|
||||
priority int
|
||||
// index 是 entry 在 heap 中的索引号
|
||||
// entry 加入 Priority Queue 后, Priority 会变化时,很有用
|
||||
// 如果 entry.priority 一直不变的话,可以删除 index
|
||||
index int
|
||||
}
|
||||
|
||||
// PQ implements heap.Interface and holds entries.
|
||||
type PQ []*entry
|
||||
|
||||
func (pq PQ) Len() int { return len(pq) }
|
||||
|
||||
func (pq PQ) Less(i, j int) bool {
|
||||
return pq[i].priority < pq[j].priority
|
||||
}
|
||||
|
||||
func (pq PQ) Swap(i, j int) {
|
||||
pq[i], pq[j] = pq[j], pq[i]
|
||||
pq[i].index = i
|
||||
pq[j].index = j
|
||||
}
|
||||
|
||||
// Push 往 pq 中放 entry
|
||||
func (pq *PQ) Push(x interface{}) {
|
||||
temp := x.(*entry)
|
||||
temp.index = len(*pq)
|
||||
*pq = append(*pq, temp)
|
||||
}
|
||||
|
||||
// Pop 从 pq 中取出最优先的 entry
|
||||
func (pq *PQ) Pop() interface{} {
|
||||
temp := (*pq)[len(*pq)-1]
|
||||
temp.index = -1 // for safety
|
||||
*pq = (*pq)[0 : len(*pq)-1]
|
||||
return temp
|
||||
}
|
||||
|
||||
// update modifies the priority and value of an entry in the queue.
|
||||
func (pq *PQ) update(entry *entry, value string, priority int) {
|
||||
entry.key = value
|
||||
entry.priority = priority
|
||||
heap.Fix(pq, entry.index)
|
||||
}
|
53
structures/PriorityQueue_test.go
Normal file
53
structures/PriorityQueue_test.go
Normal file
@ -0,0 +1,53 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_priorityQueue(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
// Some items and their priorities.
|
||||
items := map[string]int{
|
||||
"banana": 2, "apple": 1, "pear": 3,
|
||||
}
|
||||
|
||||
// Create a priority queue, put the items in it, and
|
||||
// establish the priority queue (heap) invariants.
|
||||
pq := make(PQ, len(items))
|
||||
i := 0
|
||||
for value, priority := range items {
|
||||
pq[i] = &entry{
|
||||
key: value,
|
||||
priority: priority,
|
||||
index: i,
|
||||
}
|
||||
i++
|
||||
}
|
||||
heap.Init(&pq)
|
||||
|
||||
// Insert a new item and then modify its priority.
|
||||
it := &entry{
|
||||
key: "orange",
|
||||
priority: 5,
|
||||
}
|
||||
heap.Push(&pq, it)
|
||||
pq.update(it, it.key, 0)
|
||||
|
||||
// Some items and their priorities.
|
||||
expected := []string{
|
||||
"orange",
|
||||
"apple",
|
||||
"banana",
|
||||
"pear",
|
||||
}
|
||||
|
||||
// Take the items out; they arrive in decreasing priority order.
|
||||
for pq.Len() > 0 {
|
||||
it := heap.Pop(&pq).(*entry)
|
||||
ast.Equal(expected[it.priority], it.key)
|
||||
}
|
||||
}
|
33
structures/Queue.go
Normal file
33
structures/Queue.go
Normal file
@ -0,0 +1,33 @@
|
||||
package structures
|
||||
|
||||
// Queue 是用于存放 int 的队列
|
||||
type Queue struct {
|
||||
nums []int
|
||||
}
|
||||
|
||||
// NewQueue 返回 *kit.Queue
|
||||
func NewQueue() *Queue {
|
||||
return &Queue{nums: []int{}}
|
||||
}
|
||||
|
||||
// Push 把 n 放入队列
|
||||
func (q *Queue) Push(n int) {
|
||||
q.nums = append(q.nums, n)
|
||||
}
|
||||
|
||||
// Pop 从 q 中取出最先进入队列的值
|
||||
func (q *Queue) Pop() int {
|
||||
res := q.nums[0]
|
||||
q.nums = q.nums[1:]
|
||||
return res
|
||||
}
|
||||
|
||||
// Len 返回 q 的长度
|
||||
func (q *Queue) Len() int {
|
||||
return len(q.nums)
|
||||
}
|
||||
|
||||
// IsEmpty 反馈 q 是否为空
|
||||
func (q *Queue) IsEmpty() bool {
|
||||
return q.Len() == 0
|
||||
}
|
27
structures/Queue_test.go
Normal file
27
structures/Queue_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Queue(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
q := NewQueue()
|
||||
ast.True(q.IsEmpty(), "检查新建的 q 是否为空")
|
||||
|
||||
start, end := 0, 100
|
||||
|
||||
for i := start; i < end; i++ {
|
||||
q.Push(i)
|
||||
ast.Equal(i-start+1, q.Len(), "Push 后检查 q 的长度。")
|
||||
}
|
||||
|
||||
for i := start; i < end; i++ {
|
||||
ast.Equal(i, q.Pop(), "从 q 中 pop 出数来。")
|
||||
}
|
||||
|
||||
ast.True(q.IsEmpty(), "检查 Pop 完毕后的 q 是否为空")
|
||||
}
|
33
structures/Stack.go
Normal file
33
structures/Stack.go
Normal file
@ -0,0 +1,33 @@
|
||||
package structures
|
||||
|
||||
// Stack 是用于存放 int 的 栈
|
||||
type Stack struct {
|
||||
nums []int
|
||||
}
|
||||
|
||||
// NewStack 返回 *kit.Stack
|
||||
func NewStack() *Stack {
|
||||
return &Stack{nums: []int{}}
|
||||
}
|
||||
|
||||
// Push 把 n 放入 栈
|
||||
func (s *Stack) Push(n int) {
|
||||
s.nums = append(s.nums, n)
|
||||
}
|
||||
|
||||
// Pop 从 s 中取出最后放入 栈 的值
|
||||
func (s *Stack) Pop() int {
|
||||
res := s.nums[len(s.nums)-1]
|
||||
s.nums = s.nums[:len(s.nums)-1]
|
||||
return res
|
||||
}
|
||||
|
||||
// Len 返回 s 的长度
|
||||
func (s *Stack) Len() int {
|
||||
return len(s.nums)
|
||||
}
|
||||
|
||||
// IsEmpty 反馈 s 是否为空
|
||||
func (s *Stack) IsEmpty() bool {
|
||||
return s.Len() == 0
|
||||
}
|
27
structures/Stack_test.go
Normal file
27
structures/Stack_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Stack(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
s := NewStack()
|
||||
ast.True(s.IsEmpty(), "检查新建的 s 是否为空")
|
||||
|
||||
start, end := 0, 100
|
||||
|
||||
for i := start; i < end; i++ {
|
||||
s.Push(i)
|
||||
ast.Equal(i-start+1, s.Len(), "Push 后检查 q 的长度。")
|
||||
}
|
||||
|
||||
for i := end - 1; i >= start; i-- {
|
||||
ast.Equal(i, s.Pop(), "从 s 中 pop 出数来。")
|
||||
}
|
||||
|
||||
ast.True(s.IsEmpty(), "检查 Pop 完毕后的 s 是否为空")
|
||||
}
|
219
structures/TreeNode.go
Normal file
219
structures/TreeNode.go
Normal file
@ -0,0 +1,219 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TreeNode is tree's node
|
||||
type TreeNode struct {
|
||||
Val int
|
||||
Left *TreeNode
|
||||
Right *TreeNode
|
||||
}
|
||||
|
||||
// NULL 方便添加测试数据
|
||||
var NULL = -1 << 63
|
||||
|
||||
// Ints2TreeNode 利用 []int 生成 *TreeNode
|
||||
func Ints2TreeNode(ints []int) *TreeNode {
|
||||
n := len(ints)
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
root := &TreeNode{
|
||||
Val: ints[0],
|
||||
}
|
||||
|
||||
queue := make([]*TreeNode, 1, n*2)
|
||||
queue[0] = root
|
||||
|
||||
i := 1
|
||||
for i < n {
|
||||
node := queue[0]
|
||||
queue = queue[1:]
|
||||
|
||||
if i < n && ints[i] != NULL {
|
||||
node.Left = &TreeNode{Val: ints[i]}
|
||||
queue = append(queue, node.Left)
|
||||
}
|
||||
i++
|
||||
|
||||
if i < n && ints[i] != NULL {
|
||||
node.Right = &TreeNode{Val: ints[i]}
|
||||
queue = append(queue, node.Right)
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
// GetTargetNode 返回 Val = target 的 TreeNode
|
||||
// root 中一定有 node.Val = target
|
||||
func GetTargetNode(root *TreeNode, target int) *TreeNode {
|
||||
if root == nil || root.Val == target {
|
||||
return root
|
||||
}
|
||||
|
||||
res := GetTargetNode(root.Left, target)
|
||||
if res != nil {
|
||||
return res
|
||||
}
|
||||
return GetTargetNode(root.Right, target)
|
||||
}
|
||||
|
||||
func indexOf(val int, nums []int) int {
|
||||
for i, v := range nums {
|
||||
if v == val {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("%d 不存在于 %v 中", val, nums)
|
||||
panic(msg)
|
||||
}
|
||||
|
||||
// PreIn2Tree 把 preorder 和 inorder 切片转换成 二叉树
|
||||
func PreIn2Tree(pre, in []int) *TreeNode {
|
||||
if len(pre) != len(in) {
|
||||
panic("preIn2Tree 中两个切片的长度不相等")
|
||||
}
|
||||
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := &TreeNode{
|
||||
Val: pre[0],
|
||||
}
|
||||
|
||||
if len(in) == 1 {
|
||||
return res
|
||||
}
|
||||
|
||||
idx := indexOf(res.Val, in)
|
||||
|
||||
res.Left = PreIn2Tree(pre[1:idx+1], in[:idx])
|
||||
res.Right = PreIn2Tree(pre[idx+1:], in[idx+1:])
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// InPost2Tree 把 inorder 和 postorder 切片转换成 二叉树
|
||||
func InPost2Tree(in, post []int) *TreeNode {
|
||||
if len(post) != len(in) {
|
||||
panic("inPost2Tree 中两个切片的长度不相等")
|
||||
}
|
||||
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := &TreeNode{
|
||||
Val: post[len(post)-1],
|
||||
}
|
||||
|
||||
if len(in) == 1 {
|
||||
return res
|
||||
}
|
||||
|
||||
idx := indexOf(res.Val, in)
|
||||
|
||||
res.Left = InPost2Tree(in[:idx], post[:idx])
|
||||
res.Right = InPost2Tree(in[idx+1:], post[idx:len(post)-1])
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Tree2Preorder 把 二叉树 转换成 preorder 的切片
|
||||
func Tree2Preorder(root *TreeNode) []int {
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if root.Left == nil && root.Right == nil {
|
||||
return []int{root.Val}
|
||||
}
|
||||
|
||||
res := []int{root.Val}
|
||||
res = append(res, Tree2Preorder(root.Left)...)
|
||||
res = append(res, Tree2Preorder(root.Right)...)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Tree2Inorder 把 二叉树转换成 inorder 的切片
|
||||
func Tree2Inorder(root *TreeNode) []int {
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if root.Left == nil && root.Right == nil {
|
||||
return []int{root.Val}
|
||||
}
|
||||
|
||||
res := Tree2Inorder(root.Left)
|
||||
res = append(res, root.Val)
|
||||
res = append(res, Tree2Inorder(root.Right)...)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Tree2Postorder 把 二叉树 转换成 postorder 的切片
|
||||
func Tree2Postorder(root *TreeNode) []int {
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if root.Left == nil && root.Right == nil {
|
||||
return []int{root.Val}
|
||||
}
|
||||
|
||||
res := Tree2Postorder(root.Left)
|
||||
res = append(res, Tree2Postorder(root.Right)...)
|
||||
res = append(res, root.Val)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Equal return ture if tn == a
|
||||
func (tn *TreeNode) Equal(a *TreeNode) bool {
|
||||
if tn == nil && a == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if tn == nil || a == nil || tn.Val != a.Val {
|
||||
return false
|
||||
}
|
||||
|
||||
return tn.Left.Equal(a.Left) && tn.Right.Equal(a.Right)
|
||||
}
|
||||
|
||||
// Tree2ints 把 *TreeNode 按照行还原成 []int
|
||||
func Tree2ints(tn *TreeNode) []int {
|
||||
res := make([]int, 0, 1024)
|
||||
|
||||
queue := []*TreeNode{tn}
|
||||
|
||||
for len(queue) > 0 {
|
||||
size := len(queue)
|
||||
for i := 0; i < size; i++ {
|
||||
nd := queue[i]
|
||||
if nd == nil {
|
||||
res = append(res, NULL)
|
||||
} else {
|
||||
res = append(res, nd.Val)
|
||||
queue = append(queue, nd.Left, nd.Right)
|
||||
}
|
||||
}
|
||||
queue = queue[size:]
|
||||
}
|
||||
|
||||
i := len(res)
|
||||
for i > 0 && res[i-1] == NULL {
|
||||
i--
|
||||
}
|
||||
|
||||
return res[:i]
|
||||
}
|
166
structures/TreeNode_test.go
Normal file
166
structures/TreeNode_test.go
Normal file
@ -0,0 +1,166 @@
|
||||
package structures
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
// 同一个 TreeNode 的不同表达方式
|
||||
// 1
|
||||
// / \
|
||||
// 2 3
|
||||
// / \ / \
|
||||
// 4 5 6 7
|
||||
LeetCodeOrder = []int{1, 2, 3, 4, 5, 6, 7}
|
||||
preOrder = []int{1, 2, 4, 5, 3, 6, 7}
|
||||
inOrder = []int{4, 2, 5, 1, 6, 3, 7}
|
||||
postOrder = []int{4, 5, 2, 6, 7, 3, 1}
|
||||
)
|
||||
|
||||
func Test_Ints2TreeNode(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
expected := PreIn2Tree(preOrder, inOrder)
|
||||
actual := Ints2TreeNode(LeetCodeOrder)
|
||||
ast.Equal(expected, actual)
|
||||
|
||||
actual = Ints2TreeNode([]int{})
|
||||
ast.Nil(actual)
|
||||
}
|
||||
|
||||
func Test_preIn2Tree(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
actual := Tree2Postorder(PreIn2Tree(preOrder, inOrder))
|
||||
expected := postOrder
|
||||
ast.Equal(expected, actual)
|
||||
|
||||
ast.Panics(func() { PreIn2Tree([]int{1}, []int{}) })
|
||||
|
||||
ast.Nil(PreIn2Tree([]int{}, []int{}))
|
||||
}
|
||||
|
||||
func Test_inPost2Tree(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
actual := Tree2Preorder(InPost2Tree(inOrder, postOrder))
|
||||
expected := preOrder
|
||||
ast.Equal(expected, actual)
|
||||
|
||||
ast.Panics(func() { InPost2Tree([]int{1}, []int{}) })
|
||||
|
||||
ast.Nil(InPost2Tree([]int{}, []int{}))
|
||||
}
|
||||
|
||||
func Test_tree2Ints(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
root := PreIn2Tree(preOrder, inOrder)
|
||||
|
||||
ast.Equal(preOrder, Tree2Preorder(root))
|
||||
ast.Nil(Tree2Preorder(nil))
|
||||
|
||||
ast.Equal(inOrder, Tree2Inorder(root))
|
||||
ast.Nil(Tree2Inorder(nil))
|
||||
|
||||
ast.Equal(postOrder, Tree2Postorder(root))
|
||||
ast.Nil(Tree2Postorder(nil))
|
||||
}
|
||||
|
||||
func Test_indexOf(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
ast.Equal(1, indexOf(1, []int{0, 1, 2, 3}))
|
||||
|
||||
ast.Panics(func() { indexOf(0, []int{1, 2, 3}) })
|
||||
}
|
||||
|
||||
func Test_TreeNode_Equal(t *testing.T) {
|
||||
type args struct {
|
||||
a *TreeNode
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields args
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
|
||||
{
|
||||
"相等",
|
||||
args{Ints2TreeNode([]int{1, 2, 3, 4, 5})},
|
||||
args{Ints2TreeNode([]int{1, 2, 3, 4, 5})},
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
"不相等",
|
||||
args{Ints2TreeNode([]int{1, 2, 3, 4, 5})},
|
||||
args{Ints2TreeNode([]int{1, 2, 3, NULL, 5})},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tn := tt.fields.a
|
||||
if got := tn.Equal(tt.args.a); got != tt.want {
|
||||
t.Errorf("TreeNode.Equal() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetTargetNode(t *testing.T) {
|
||||
ints := []int{3, 5, 1, 6, 2, 0, 8, NULL, NULL, 7, 4}
|
||||
root := Ints2TreeNode(ints)
|
||||
|
||||
type args struct {
|
||||
root *TreeNode
|
||||
target int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *TreeNode
|
||||
}{
|
||||
|
||||
{
|
||||
"找到 root.Right.Right",
|
||||
args{
|
||||
root: root,
|
||||
target: 8,
|
||||
},
|
||||
root.Right.Right,
|
||||
},
|
||||
|
||||
{
|
||||
"找到 root.Left.Left",
|
||||
args{
|
||||
root: root,
|
||||
target: 6,
|
||||
},
|
||||
root.Left.Left,
|
||||
},
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetTargetNode(tt.args.root, tt.args.target); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetTargetNode() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Tree2ints(t *testing.T) {
|
||||
ast := assert.New(t)
|
||||
|
||||
root := PreIn2Tree(preOrder, inOrder)
|
||||
actual := LeetCodeOrder
|
||||
expected := Tree2ints(root)
|
||||
ast.Equal(expected, actual)
|
||||
}
|
Reference in New Issue
Block a user