Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Day434 #871

Merged
merged 2 commits into from
Jan 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,5 +426,6 @@ problems from
* [Day 427](https://github.com/vaskoz/dailycodingproblem-go/issues/861)
* [Day 428](https://github.com/vaskoz/dailycodingproblem-go/issues/864)
* [Day 429](https://github.com/vaskoz/dailycodingproblem-go/issues/866)
* [Day 434](https://github.com/vaskoz/dailycodingproblem-go/issues/870)
* [Day 435](https://github.com/vaskoz/dailycodingproblem-go/issues/868)

128 changes: 128 additions & 0 deletions day434/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package day434

import "errors"

var errNoAnswer = errors.New("no answer exists")

// ErrNoAnswer returns the error returned for no answer.
func ErrNoAnswer() error {
return errNoAnswer
}

// BinaryTree is a binary tree of integers.
type BinaryTree struct {
Value int
Left, Right *BinaryTree
}

// FloorRecursive returns the highest element in the tree less
// than or equal to the target.
// Returns an error if no answer exists.
func FloorRecursive(root *BinaryTree, target int) (int, error) {
if root == nil {
return 0, errNoAnswer
}

if target == root.Value {
return target, nil
}

if target < root.Value {
return FloorRecursive(root.Left, target)
}

ans, err := FloorRecursive(root.Right, target)
if err != nil && root.Value <= target {
return root.Value, nil
}

return ans, err
}

// FloorFaster returns the highest element in the tree less
// than or equal to the target.
// Returns an error if no answer exists.
func FloorFaster(root *BinaryTree, target int) (int, error) {
curr := root

var candidate *BinaryTree

for {
if curr.Value == target {
return curr.Value, nil
}

if target < curr.Value {
if curr.Left != nil {
curr = curr.Left
} else {
return 0, errNoAnswer
}
} else {
candidate = curr
if curr.Right != nil {
curr = curr.Right
} else if candidate != nil {
return candidate.Value, nil
}
}
}
}

// CeilingRecursive returns the lowest element in the tree greater
// than or equal to the target.
// Returns an error if no answer exists.
func CeilingRecursive(root *BinaryTree, target int) (int, error) {
if root == nil {
return 0, errNoAnswer
}

if target == root.Value {
return target, nil
}

if target < root.Value {
ans, err := CeilingRecursive(root.Left, target)
if err != nil && root.Value >= target {
return root.Value, nil
}

return ans, err
}

return CeilingRecursive(root.Right, target)
}

// CeilingFaster returns the lowest element in the tree greater
// than or equal to the target.
// Returns an error if no answer exists.
func CeilingFaster(root *BinaryTree, target int) (int, error) {
curr := root

var candidate *BinaryTree

for {
if curr.Value == target {
return curr.Value, nil
}

if target < curr.Value {
candidate = curr

if curr.Left != nil {
curr = curr.Left
} else if candidate != nil {
return candidate.Value, nil
}
} else {
switch {
case curr.Right != nil:
curr = curr.Right
case candidate != nil:
return candidate.Value, nil
default:
return 0, errNoAnswer
}
}
}
}
150 changes: 150 additions & 0 deletions day434/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package day434

import "testing"

// nolint
var testcases = []struct {
root *BinaryTree
target int
expectedFloor int
expectedFloorErr error
expectedCeil int
expectedCeilErr error
}{
{
&BinaryTree{
11,
&BinaryTree{9, nil, nil},
&BinaryTree{12, nil, nil},
},
10,
9,
nil,
11,
nil,
},
{
&BinaryTree{
11,
&BinaryTree{9, nil, nil},
&BinaryTree{12, nil, nil},
},
12,
12,
nil,
12,
nil,
},
{
&BinaryTree{
11,
&BinaryTree{9, nil, nil},
&BinaryTree{12, nil, nil},
},
13,
12,
nil,
0,
ErrNoAnswer(),
},
{
&BinaryTree{
11,
&BinaryTree{9, nil, nil},
&BinaryTree{12, nil, nil},
},
8,
0,
ErrNoAnswer(),
9,
nil,
},
{
&BinaryTree{
12,
&BinaryTree{9, nil, nil},
&BinaryTree{14, nil, nil},
},
11,
9,
nil,
12,
nil,
},
}

func TestFloorRecursive(t *testing.T) {
t.Parallel()

for tcid, tc := range testcases {
if result, err := FloorRecursive(tc.root, tc.target); result != tc.expectedFloor ||
err != tc.expectedFloorErr {
t.Errorf("TCID %d Expected (%v,%v), got (%v,%v)", tcid, tc.expectedFloor, tc.expectedFloorErr, result, err)
}
}
}

func BenchmarkFloorRecursive(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
FloorRecursive(tc.root, tc.target) // nolint
}
}
}

func TestFloorFaster(t *testing.T) {
t.Parallel()

for tcid, tc := range testcases {
if result, err := FloorFaster(tc.root, tc.target); result != tc.expectedFloor ||
err != tc.expectedFloorErr {
t.Errorf("TCID %d Expected (%v,%v), got (%v,%v)", tcid, tc.expectedFloor, tc.expectedFloorErr, result, err)
}
}
}

func BenchmarkFloorFaster(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
FloorRecursive(tc.root, tc.target) // nolint
}
}
}

func TestCeilingRecursive(t *testing.T) {
t.Parallel()

for tcid, tc := range testcases {
if result, err := CeilingRecursive(tc.root, tc.target); result != tc.expectedCeil ||
err != tc.expectedCeilErr {
t.Errorf("TCID %d Expected (%v,%v), got (%v,%v)", tcid, tc.expectedCeil, tc.expectedCeilErr, result, err)
}
}
}

func BenchmarkCeiling(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
CeilingRecursive(tc.root, tc.target) // nolint
}
}
}

func TestCeilingFaster(t *testing.T) {
t.Parallel()

for tcid, tc := range testcases {
if result, err := CeilingFaster(tc.root, tc.target); result != tc.expectedCeil ||
err != tc.expectedCeilErr {
t.Errorf("TCID %d Expected (%v,%v), got (%v,%v)", tcid, tc.expectedCeil, tc.expectedCeilErr, result, err)
}
}
}

func BenchmarkCeilingFaster(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
CeilingFaster(tc.root, tc.target) // nolint
}
}
}