Skip to content
Open

CC29 #30

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
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
language: node_js
node_js:
- "9"

script:
- npm test
86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# data-structures-and-algorithms

* [travis](https://www.travis-ci.com/MeStock/data-structures-and-algorithms)

<h2>Overview</h2>
<p>This repo is a place to organize completed code challenges. Within the code challenges folder, you can find examples of different data structure and algorithm problems with their optimzed solutions.</p>

Expand Down Expand Up @@ -159,3 +161,87 @@ Add in some conditionals for edge cases:

## Solution
![whiteboard fifo animal shelter](/assets/fifo-animal-shelter.jpg)

# Trees
Trees are a type of data structure made up of `nodes`. A binary tree start with a root node that has a pointer for a left child and right child node. Each child node also has a set of pointers toward a left child and right child node. A binary search tree is a tree that adds nodes to the left of the parent node its value is less than the parent - or to the right of the parent node if its value is greater than the parent.

## Challenge
Create a Binary Tree class with preorder, inorder, and post order methods.
Create a Binary Search Tree class with add and contain methods.

## Approach & Efficiency
Binary Tree: Traversing the tree will have a O(n) in time, where n is the number of nodes in the tree and O(1) in space. Similarly, inserting into the tree will have O(n) in time.

BinarySearch Tree: Travering the tree will have an O(n) in time, where n is the number of nodes in the tree and O(1) in space. However inserting into the tree will have O(h) in time, where h is the height of the tree.

## API
Binary Trees:
preOrder(): returns an array of values stored in the tree in the order: root, left right.
inOrder(): returns an array of values stored in the tree in the order: left, root, right.
postOrder(): returns an array of values stored in the tree in the order: left, right, root.

Binary Search Trees:
add(value): traverses through the tree - going right if the new value is less than the current nodes value or going left if the new value is greater than the current nodes value - until a leaf is found. Then inserts the new value either to the right or left of the leaf node depending on its value.

contains(value): traverses through the tree and returns true if the tree contains the value. returns false if tree is empty, an invalid value is given, or the value was not found.

# Fizzbuzz Tree
Create a function called FizzbuzzTree that takes in the root of a tree. It traverses the tree and replaces values divisible by 3 with the string 'fizz', values divisible by 5 are replaced with 'buzz', and values divisible by 3 and 5 are replaced with 'fizzbuzz'.

## Challenge
* traverse tree, checking the type of the value within each node. If the value is a number - check the conditions listed above. Modify tree in place.

## Approach & Efficiency
To modify the tree in place, I used recursion to traverse the tree.
Time: O(n) - where n is the number of nodes in the tree
Space: O(1) - Modify the tree in place - however, O(n) where n is the call stack since this function uses recursion.

Add in some conditionals for edge cases:
* Do not traverse is the tree is empty
* Do not check if values are divisible if they are not numbers

## Solution
![whiteboard fizzbuzz tree](/assets/fizzbuzzTree.jpeg)

# Find the depth of a value within a Binary Tree
Create a function called depth of value that takes in the root of a tree and a value. It will search the tree for a value and if found return the depth at which it was found.

## Challenge
* traverse tree, checking values of each node and tracking the depth. Using recursion to keep track of the depth going down the tree and passing the depth back through the call stack when the value is found.

## Approach & Efficiency
Time: O(n) - where n is the number of nodes within the tree.
Space: O(H) - where H is the height of the tree.

Add in some conditionals for edge cases:
* Do not traverse is the tree is empty
* Return null if no value is found

## Solution
![whiteboard depth of value](/assets/depthOfValue.jpg)

# Reverse an Array
The reverse array function will take in an array as a parameter and return the elements of the array in reverser order.

## Challenge
Modify array in place

## Approach & Efficiency
I knew that I needed some sort of looping mechanism, so I started by visualizing the input and output of the array. <br><br>
I: [1,2,3,4,5] <br>
O: [5,4,3,2,1] <br><br>
Keeping track of the front index and back index and making swaps was the optimal solution.

LOOP 1:
[5,2,3,4,1]
<br><br>
LOOP 2:
[5,4,3,2,1]
<br><br>
LOOP 3: reached the middle of the array so return the current state of the array.

The time complexity for this is O(n) where n is half the length of the list and space complexity is O(1) because we are modifying in place.
You can also solve this problem using built in array methods (reverse, push, pop) or recursively but the space/time complexities are not as efficient.

## Solution
![whiteboard array reverse](/assets/more-array-reverse.jpg)
64 changes: 32 additions & 32 deletions __tests__/append-insert-before-after.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,35 @@ describe('Linked list', () => {
const test = new LinkedList();
expect(test.append('test')).toEqual(expect.objectContaining(test));
});
xit('should properly insert before the first node of the list', () => {
const test = new LinkedList();
test.append('head');
test.append('first node');
test.append('second node');
test.insertBefore('head','inserted before node');
expect(test.value).toBe('inserted before node');
});
xit('should properly insert before i in the middle of the list', () => {
const test = new LinkedList();
test.append('head');
test.append('first node');
test.append('second node');
test.insertBefore('first node','inserted node');
expect(test.next.value).toEqual('inserted node');
});
xit('should properly insert after the last node of the list', () => {
const test = new LinkedList();
test.append('head');
test.append('first node');
test.insertAfter('first node', 'inserted node');
expect(test.next.next.value).toEqual('inserted node');
});
xit('should properly insert in the middle of the list', () => {
const test = new LinkedList();
test.append('head');
test.append('first node');
test.append('second node');
test.insertAfter('first node', 'inserted node');
expect(test.next.next.value).toEqual('inserted node');
});
});
// xit('should properly insert before the first node of the list', () => {
// const test = new LinkedList();
// test.append('head');
// test.append('first node');
// test.append('second node');
// test.insertBefore('head','inserted before node');
// expect(test.value).toBe('inserted before node');
// });
// xit('should properly insert before i in the middle of the list', () => {
// const test = new LinkedList();
// test.append('head');
// test.append('first node');
// test.append('second node');
// test.insertBefore('first node','inserted node');
// expect(test.next.value).toEqual('inserted node');
// });
// xit('should properly insert after the last node of the list', () => {
// const test = new LinkedList();
// test.append('head');
// test.append('first node');
// test.insertAfter('first node', 'inserted node');
// expect(test.next.next.value).toEqual('inserted node');
// });
// xit('should properly insert in the middle of the list', () => {
// const test = new LinkedList();
// test.append('head');
// test.append('first node');
// test.append('second node');
// test.insertAfter('first node', 'inserted node');
// expect(test.next.next.value).toEqual('inserted node');
// });
});
31 changes: 31 additions & 0 deletions __tests__/array-reverse.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const arrayReverse1 = require('../code-challenges/array-reverse/array-reverse.js').reverseArray;
const arrayReverse2 = require('../code-challenges/array-reverse/array-reverse.js').stretchGoal;
const arrayReverse3 = require('../code-challenges/array-reverse/more-array-reverse.js');
const reversedTest = ['d', 'c', 'b', 'a'];


describe('Array Reverse', () => {
it('should reverse an array with one element', () => {
const test = ['a'];
expect(arrayReverse1(test)).toEqual(['a']);
expect(arrayReverse2(test)).toEqual(['a']);
expect(arrayReverse3(test)).toEqual(['a']);
});

it('should reverse any array of any size', () => {
const test1 = ['a', 'b', 'c', 'd'];
const test2 = ['a', 'b', 'c', 'd'];
const test3 = ['a', 'b', 'c', 'd'];
expect(arrayReverse1(test1)).toEqual(reversedTest);
expect(arrayReverse2(test2)).toEqual(reversedTest);
expect(arrayReverse3(test3)).toEqual(reversedTest);
});

it('should return null if no array is given', () => {
expect(arrayReverse1()).toBeNull();
expect(arrayReverse2()).toBeNull();
expect(arrayReverse3()).toBeNull();
});
});
38 changes: 38 additions & 0 deletions __tests__/depth-of-tree.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

const Node = require('../code-challenges/tree/node.js');
const BinaryTree = require('../code-challenges/tree/tree.js');
const depthOfValue = require('../code-challenges/depth-of-tree/depth-of-tree.js');


describe('Depth of value in tree', () => {
it('should create new trees', () => {
const test = new BinaryTree();
expect(test).toBeInstanceOf(BinaryTree);
});
it('should successfully create empty trees', () => {
const test = new BinaryTree();
expect(test.root.value).toBeUndefined();
});
it('should successfully return null if tree is empty', () => {
const test = new BinaryTree();
expect(depthOfValue(test.root, 5)).toBeNull();
});
it('should successfully return null if the value was not found', () => {
const test = new BinaryTree(1);
test.root.left = new Node(4);
test.root.right = new Node(5);
expect(depthOfValue(test.root, 3)).toBeNull();
});
it('should return null if the inputs are invalide', () => {
const test = new BinaryTree();
expect(depthOfValue(test)).toBeNull();
expect(depthOfValue()).toBeNull();
})
it('should successfully return the depth of tree', () => {
const test = new BinaryTree(1);
test.root.left = new Node(7);
test.root.right = new Node(15);
expect(depthOfValue(test.root, 15)).toBe(1);
});
});
50 changes: 50 additions & 0 deletions __tests__/fizzbuzz-tree.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict';

const Node = require('../code-challenges/tree/node.js');
const BinaryTree = require('../code-challenges/tree/tree.js');
const fizzbuzzTree = require('../code-challenges/fizzbuzz-tree/fizzbuzz-tree.js');


describe('Fizzbuzz Tree', () => {
it('should create new trees', () => {
const test = new BinaryTree();
expect(test).toBeInstanceOf(BinaryTree);
});
it('should successfully create empty trees', () => {
const test = new BinaryTree();
expect(test.root.value).toBeUndefined();
});
it('should successfully change numbers divisible by 3 to fizz', () => {
const test = new BinaryTree(1);
test.root.left = new Node(3);
test.root.right = new Node(4);
fizzbuzzTree(test.root);
expect(test.root.left.value).toBe('fizz');
expect(test.root.right.value).toBe(4);
});
it('should successfully change numbers divisible by 5 to buzz', () => {
const test = new BinaryTree(1);
test.root.left = new Node(4);
test.root.right = new Node(5);
fizzbuzzTree(test.root);
expect(test.root.left.value).toBe(4);
expect(test.root.right.value).toBe('buzz');
});
it('should successfully change numbers divisible by 5 and 3 to fizzbuzz', () => {
const test = new BinaryTree(1);
test.root.left = new Node(7);
test.root.right = new Node(15);
fizzbuzzTree(test.root);
expect(test.root.left.value).toBe(7);
expect(test.root.right.value).toBe('fizz buzz');
});
it('should not change anything that isn\'t divisible by 3 or 5', () => {
const test = new BinaryTree(1);
test.root.left = new Node(4);
test.root.right = new Node(7);
fizzbuzzTree(test.root);
expect(test.root.value).toBe(1);
expect(test.root.left.value).toBe(4);
expect(test.root.right.value).toBe(7);
});
});
89 changes: 89 additions & 0 deletions __tests__/tree.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
'use strict';


/*

Can successfully instantiate an empty tree
Can successfully instantiate a tree with a single root node
Can successfully add a left child and right child to a single root node
Can successfully return a collection from a preorder traversal
Can successfully return a collection from an inorder traversal
Can successfully return a collection from a postorder traversal

*/

const Node = require('../code-challenges/tree/node.js');
const BinaryTree = require('../code-challenges/tree/tree.js');
const BinarySearchTree = require('../code-challenges/tree/searchTree.js');

describe('Trees', () => {

describe('Nodes', () => {
it('should create new nodes', () => {
expect(new Node()).toBeInstanceOf(Node);
});
});

describe('Binary Trees', () => {
it('should create new trees', () => {
const test = new BinaryTree();
expect(test).toBeInstanceOf(BinaryTree);
});
it('should successfully create empty trees', () => {
const test = new BinaryTree();
expect(test.root.value).toBeUndefined();
});
it('should successfully add a left child and right child to a root', () => {
const test = new BinaryTree('root');
test.root.left = new Node('left');
test.root.right = new Node('right');
expect(test.root.left.value).toBe('left');
expect(test.root.right.value).toBe('right');
});
it('should successfully return a collection of preordered values', () => {
const test = new BinaryTree('root');
test.root.left = new Node('left');
test.root.right = new Node('right');
const result = test.preOrder();
expect(result).toEqual(['root', 'left', 'right']);
});
it('should successfully return a collection of inordered values', () => {
const test = new BinaryTree('root');
test.root.left = new Node('left');
test.root.right = new Node('right');
const result = test.inOrder();
expect(result).toEqual(['left', 'root', 'right']);
});
it('should successfully return a collection of postordered values', () => {
const test = new BinaryTree('root');
test.root.left = new Node('left');
test.root.right = new Node('right');
const result = test.postOrder();
expect(result).toEqual(['left', 'right', 'root']);
});
});

describe('Binary Search Trees', () => {
it('should create new search tree', () => {
const test = new BinarySearchTree();
expect(test).toBeInstanceOf(BinarySearchTree);
});

it('should successfully add to the tree in the correct order', () => {
const test = new BinarySearchTree(100);
test.add(50); //first node to the left
test.add(10); //node to the left of 50
test.add(60); //node to the right of 50
test.add(200); //first node to the right
test.add(150); //node to the left of 200
test.add(300); //node to the right of 200
expect(test.root.left.value).toEqual(50);
expect(test.root.left.left.value).toEqual(10);
expect(test.root.left.right.value).toEqual(60);
expect(test.root.right.value).toEqual(200);
expect(test.root.right.left.value).toEqual(150);
expect(test.root.right.right.value).toEqual(300);

});
});
});
Binary file added assets/depthOfValue.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/fizzbuzzTree.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/more-array-reverse.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading