diff --git a/README.md b/README.md index 543982e..bdf2a7c 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,4 @@ problems from * [Day 40](https://github.com/vaskoz/dailycodingproblem-go/issues/87) * [Day 41](https://github.com/vaskoz/dailycodingproblem-go/issues/90) * [Day 42](https://github.com/vaskoz/dailycodingproblem-go/issues/93) +* [Day 43](https://github.com/vaskoz/dailycodingproblem-go/issues/95) diff --git a/day43/problem.go b/day43/problem.go new file mode 100644 index 0000000..a880e22 --- /dev/null +++ b/day43/problem.go @@ -0,0 +1,56 @@ +package day43 + +import "fmt" + +var errStackEmpty = fmt.Errorf("Stack is empty") + +// maxIntStack is implemented using O(N) extra memory. +type maxIntStack struct { + stack []int +} + +// MaxIntStack represents that API of a stack of ints that push, pop and find the max value. +type MaxIntStack interface { + Push(val int) + Pop() (int, error) + Max() (int, error) +} + +// NewMaxIntStack returns a new instance. +func NewMaxIntStack() MaxIntStack { + return &maxIntStack{} +} + +func (mis *maxIntStack) Push(val int) { + var max int + if len(mis.stack) == 0 { + max = val + } else { + max = mis.stack[len(mis.stack)-2] + if val > max { + max = val + } + } + mis.stack = append(mis.stack, max, val) +} + +func (mis *maxIntStack) Pop() (int, error) { + if len(mis.stack) == 0 { + return 0, StackEmptyError() + } + var result int + result, mis.stack = mis.stack[len(mis.stack)-1], mis.stack[:len(mis.stack)-2] + return result, nil +} + +func (mis *maxIntStack) Max() (int, error) { + if len(mis.stack) == 0 { + return 0, StackEmptyError() + } + return mis.stack[len(mis.stack)-2], nil +} + +// StackEmptyError returns the instance of the error representing an empty stack. +func StackEmptyError() error { + return errStackEmpty +} diff --git a/day43/problem_test.go b/day43/problem_test.go new file mode 100644 index 0000000..bb9f895 --- /dev/null +++ b/day43/problem_test.go @@ -0,0 +1,53 @@ +package day43 + +import "testing" + +var testcases = []struct { + input []int + max []int +}{ + {[]int{1, 2, 3, 4, 5, 6}, []int{1, 2, 3, 4, 5, 6}}, +} + +func TestMaxIntStack(t *testing.T) { + t.Parallel() + for tcid, tc := range testcases { + stack := NewMaxIntStack() + for i, push := range tc.input { + stack.Push(push) + if max, err := stack.Max(); err != nil || max != tc.max[i] { + t.Errorf("TC%d push expected,got max (%d,%d) error should be nil (%v)", + tcid, tc.max[i], max, err) + } + } + for i := range tc.input { + if max, err := stack.Max(); err != nil || max != tc.max[len(tc.max)-1-i] { + t.Errorf("TC%d pre-pop expected,got max (%d,%d) error should be nil (%v)", + tcid, tc.max[len(tc.max)-1-i], max, err) + } + if val, err := stack.Pop(); err != nil || val != tc.input[len(tc.input)-1-i] { + t.Errorf("TC%d pop expected,got val (%d,%d) error should be nil (%v)", + tcid, tc.input[len(tc.input)-1-i], val, err) + } + } + if _, err := stack.Pop(); err != StackEmptyError() { + t.Errorf("Stack should be empty and return an error on Pop()") + } + if _, err := stack.Max(); err != StackEmptyError() { + t.Errorf("Stack should be empty and return an error on Max()") + } + } +} + +func BenchmarkMaxIntStack(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, tc := range testcases { + stack := NewMaxIntStack() + for _, push := range tc.input { + stack.Push(push) + stack.Max() + stack.Pop() + } + } + } +}