-
-
-
-
-
-
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..565fa8c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+node_js:
+ - "9"
+
+script:
+ - npm test
\ No newline at end of file
diff --git a/README.md b/README.md
index 5ce05db..e291d39 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# data-structures-and-algorithms
+* [travis](https://www.travis-ci.com/MeStock/data-structures-and-algorithms)
+
Overview
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.
@@ -218,3 +220,98 @@ Add in some conditionals for edge cases:
## Solution

+# 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.
+ I: [1,2,3,4,5]
+ O: [5,4,3,2,1]
+Keeping track of the front index and back index and making swaps was the optimal solution.
+
+LOOP 1:
+[5,2,3,4,1]
+
+LOOP 2:
+[5,4,3,2,1]
+
+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
+
+
+# Find Sum of Integers
+Given an array and key, find the first pair of values within the array that add up and equal the key.
+
+## Challenge
+Modify array in place
+
+## Approach & Efficiency
+I used a hashmap to implement this search. Add all the values to a hashmap. Iterate through array, calculate the difference between each index of the array and the key. Use the hashmap to check if the difference exists within the map.
+
+Time complexity: O(n) where n is the length of the array
+Space complexity: O(n) where n is the length of the array
+
+The brure force method for this problem is to check every single pair within the array using nesed for loops. This would result in time complexity of O(n^2) and space complexity of O(1). Depending on individual cases, you would consider this case to save space.
+
+## Solution
+
+
+# Hashtables
+We mob programmed this challenge. Group members: Melissa Stock, Bonnie Wang, Jagdeep Singh, Rebecca Peterson, Joe Jemmely
+Implement a hashtable with the following built in methods : add(key, value), get(key), contains(key), and hash(key);
+
+## Challenge
+* add(key, value) returns the value that was just added
+* get(key) returns the value associated with the key
+* contains(key) returns true/false if the hashtable contains a value with the associated key
+* hash(key) returns an index associated with the unique hashed key
+
+## Approach & Efficiency
+* add(key, value) Time: O(L) where L is the length of the string Space: O(1) *if you ignore the hashing Time: O(1)
+* get(key) Time: O(L) where L is the length of the string Space: O(1) *if you ignore the hashing Time: O(1)
+* contains(key) Time: O(L) where L is the length of the string Space: O(1) *if you ignore the hashing Time: O(1)
+* hash(key) Time: O(L) where L is the length of the string Space: O(1)
+
+# Find Tree Path
+Given a start and an end value, traverse a tree and return a linked list representation of the path between the start and end value.
+
+## Challenge
+* Traverse the tree
+* Keep track of values
+* Create a linked list of values for the path
+* Add/remove values that belong in path
+
+## Approach & Efficiency
+Broke the problem into several smaller problems listed above to identify an approach. I used recursion to traverse the tree and modified the linked list in place to keep track of values within the given path.
+
+Time complexity: O(H) where H is the height of the tree
+Space complexity: O(n) where n is the length of the linked list
+
+## Solution
+
+
+# Find Intersections Between Two Trees
+Given two binary trees, find all the intersections between the two. Meaning, return all the common values that they share between them.
+
+## Challenge
+* Traverse tree 1
+ * Add all its values into a set
+ * Return the set
+* Traverse tree 2
+ * At eact node - if the value exists in the previous set
+ * add that value to new set
+ * Return new set
+* Return the new set
+
+## Approach & Efficiency
+Broke the problem into 3 functions listed above. Time complexity O(n) where n is the sum of nodes between the two trees. Space complexity O(m) where m is the the larger of two - either the height of the second tree or the number of nodes in the first tree.
+
+## Solution
+
\ No newline at end of file
diff --git a/__tests__/append-insert-before-after.test.js b/__tests__/append-insert-before-after.test.js
index b4b355d..d28ae1c 100644
--- a/__tests__/append-insert-before-after.test.js
+++ b/__tests__/append-insert-before-after.test.js
@@ -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');
- });
-});
\ No newline at end of file
+ // 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');
+ // });
+});
diff --git a/__tests__/array-reverse.test.js b/__tests__/array-reverse.test.js
new file mode 100644
index 0000000..43f0393
--- /dev/null
+++ b/__tests__/array-reverse.test.js
@@ -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();
+ });
+});
diff --git a/__tests__/findSumOfInts.test.js b/__tests__/findSumOfInts.test.js
new file mode 100644
index 0000000..c06a452
--- /dev/null
+++ b/__tests__/findSumOfInts.test.js
@@ -0,0 +1,22 @@
+'use strict';
+
+const findSumOfInts = require('../code-challenges/findSumOfInts/findSumOfInts.js');
+
+describe('find sum of integers', () => {
+ it('should find 2 numbers inside an array that add up to the key', () => {
+ const test = [1,4,8,3,7,2,0,-1];
+ expect(findSumOfInts(test, 11)).toEqual([4,7]);
+ });
+
+ it('should return null if inputs are not valid', () => {
+ expect(findSumOfInts()).toBeNull();
+ expect(findSumOfInts(1,2)).toBeNull();
+ expect(findSumOfInts([1,2,3], 'not a number')).toBeNull();
+ expect(findSumOfInts([], 4)).toBeNull();
+ });
+
+ it('should find the first pair that add up to the key', () => {
+ const test = [1,2,4,-1];
+ expect(findSumOfInts(test, 3)).toEqual([1,2]);
+ });
+});
diff --git a/__tests__/findTreeIntersection.test.js b/__tests__/findTreeIntersection.test.js
new file mode 100644
index 0000000..4d50edc
--- /dev/null
+++ b/__tests__/findTreeIntersection.test.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const findTreeIntersection = require('../code-challenges/findTreeIntersection/findTreeIntersection.js');
+const BinaryTree = require('../code-challenges/tree/tree.js');
+const Node = require('../code-challenges/tree/node.js');
+
+describe('Find all intersections within two trees', () => {
+ it('should return a set of common values between the trees', () => {
+ const test1 = new BinaryTree(1);
+ test1.root.right = new Node(2);
+ test1.root.left = new Node(3);
+ const test2 = new BinaryTree(2);
+
+ const answer = new Set();
+ answer.add(2);
+
+ expect(findTreeIntersection(test1, test2)).toEqual(answer);
+ });
+
+ it('should return null if there are invalid inputs', () => {
+ const test = new BinaryTree();
+
+ expect(findTreeIntersection()).toBeNull();
+ expect(findTreeIntersection(test)).toBeNull();
+ });
+
+ it('should return an empty set if no common values are found', () => {
+ const test1 = new BinaryTree(1);
+ const test2 = new BinaryTree(2);
+
+ expect(findTreeIntersection(test1, test2)).toEqual(new Set());
+ });
+
+});
diff --git a/__tests__/findTreePath.test.js b/__tests__/findTreePath.test.js
new file mode 100644
index 0000000..019ad10
--- /dev/null
+++ b/__tests__/findTreePath.test.js
@@ -0,0 +1,53 @@
+'use strict';
+const BTnode = require('../code-challenges/tree/node.js');
+const BinaryTree = require('../code-challenges/tree/tree.js');
+const findTreePath = require('../code-challenges/findTreePath/findTreePath.js');
+const LinkedList = require('../code-challenges/linked-list/insert-include-print.js');
+
+describe('finding the path between two numbers in a binary tree', () => {
+ it('should return a linked list representation of the path', () => {
+ let test = new BinaryTree(1);
+ test = test.root;
+ test.right = new BTnode(10);
+ test.right.right = new BTnode(4);
+ test.right.right.right = new BTnode(8);
+
+ test.left = new BTnode(15);
+ test.left.left = new BTnode(6);
+ test.left.left.left = new BTnode(7);
+
+ expect(findTreePath(test, 10, 8)).toBeInstanceOf(LinkedList);
+ });
+
+ it('should return null if the input is invalid', () => {
+ let test = new BinaryTree(1);
+
+ expect(findTreePath()).toBeNull();
+ expect(findTreePath(test)).toBeNull();
+ expect(findTreePath(test, 1)).toBeNull();
+ });
+
+ it('should return null if no path is found', () => {
+ let test = new BinaryTree(1);
+ test = test.root;
+ test.right = new BTnode(10);
+ test.right.right = new BTnode(4);
+ test.right.right.right = new BTnode(8);
+
+ test.left = new BTnode(15);
+ test.left.left = new BTnode(6);
+ test.left.left.left = new BTnode(7);
+ expect(findTreePath(test, 2, 500).head).toBeNull();
+ });
+});
+
+
+let test = new BinaryTree(1);
+test = test.root;
+test.right = new BTnode(10);
+test.right.right = new BTnode(4);
+test.right.right.right = new BTnode(8);
+
+test.left = new BTnode(15);
+test.left.left = new BTnode(6);
+test.left.left.left = new BTnode(7);
diff --git a/__tests__/hashTables.test.js b/__tests__/hashTables.test.js
new file mode 100644
index 0000000..7c3b38a
--- /dev/null
+++ b/__tests__/hashTables.test.js
@@ -0,0 +1,53 @@
+'use strict';
+
+/*
+
+Write tests to prove the following functionality:
+
+Adding a key/value to your hashtable results in the value being in the data structure
+Retrieving based on a key returns the value stored
+Successfully returns null for a key that does not exist in the hashtable
+Successfully handle a collision within the hashtable
+Successfully retrieve a value from a bucket within the hashtable that has a collision
+Successfully hash a key to an in-range value
+
+*/
+
+const HashTable = require('../code-challenges/hashtables/hashtables.js');
+
+describe('Hash Tables', () => {
+ it('should add a key/value', () => {
+ const test = new HashTable();
+ expect(test.add('key', 'value')).toEqual('value');
+ });
+
+ it('should return the value associated with the key', () => {
+ const test = new HashTable();
+ test.add('key', 'value');
+ expect(test.get('key')).toEqual('value');
+ });
+
+ it('successfully return null for a key that does not exist in the table', () => {
+ const test = new HashTable();
+ test.add('key', 'value');
+ expect(test.get('not a key')).toBeNull();
+ });
+
+ it('successfully handle a collision within the hashtable', () => {
+ const test = new HashTable();
+ test.add('key', 'value');
+ expect(test.data[61].nextkey = 'next value').toEqual('next value');
+ });
+
+ it('successfully retrieves a value from a bucket within the hashtable that has a collision', () => {
+ const test = new HashTable();
+ test.add('key', 'value');
+ test.data[61].nextkey = 'next value';
+ expect(test.get('key')).toEqual('value');
+ });
+
+ it('successfully hash a key to an in-range value', () => {
+ const test = new HashTable();
+ expect(test.hash('key')).toEqual(61);
+ });
+});
diff --git a/assets/findSumOfInts.jpg b/assets/findSumOfInts.jpg
new file mode 100644
index 0000000..037e4de
Binary files /dev/null and b/assets/findSumOfInts.jpg differ
diff --git a/assets/findTreeIntersection.jpg b/assets/findTreeIntersection.jpg
new file mode 100644
index 0000000..ef59111
Binary files /dev/null and b/assets/findTreeIntersection.jpg differ
diff --git a/assets/findTreePath.jpg b/assets/findTreePath.jpg
new file mode 100644
index 0000000..7470897
Binary files /dev/null and b/assets/findTreePath.jpg differ
diff --git a/assets/more-array-reverse.jpg b/assets/more-array-reverse.jpg
new file mode 100644
index 0000000..35046e0
Binary files /dev/null and b/assets/more-array-reverse.jpg differ
diff --git a/code-challenges/array-reverse/array-reverse.js b/code-challenges/array-reverse/array-reverse.js
index e42dc16..08b6f0d 100644
--- a/code-challenges/array-reverse/array-reverse.js
+++ b/code-challenges/array-reverse/array-reverse.js
@@ -1,6 +1,8 @@
// Write a function called reverseArray which takes an array as an argument. Without utilizing any of the built-in methods available to your language, return an array with elements in reversed order.
function reverseArray(arr){
+ if(!arr) return null;
+ if(arr.length === 1) return arr;
let result = [];
for(let i = arr.length - 1; i >= 0; i--){
result.push(arr[i]);
@@ -8,12 +10,13 @@ function reverseArray(arr){
return result;
}
-console.log(reverseArray([1,2,3,4,5]));
// STRETCH GOAL
// Once you’ve achieved a working solution, implement the same feature with a different methodology. (Hint: what different techniques do you have when working with arrays? Recursion, loops, indexes, modifying the array input directly…)
function stretchGoal(arr){
+ if(!arr) return null;
+ if(arr.length === 1) return arr;
let result = [];
let length = arr.length;
for(let i = 0; i < length; i++){
@@ -23,4 +26,5 @@ function stretchGoal(arr){
return result;
}
-console.log(stretchGoal([1,2,3,4,5]));
+module.exports = {reverseArray, stretchGoal};
+
diff --git a/code-challenges/array-reverse/more-array-reverse.js b/code-challenges/array-reverse/more-array-reverse.js
new file mode 100644
index 0000000..c3d8ed6
--- /dev/null
+++ b/code-challenges/array-reverse/more-array-reverse.js
@@ -0,0 +1,17 @@
+'use strict';
+
+function reverseAnArray(array){
+ if(!array) return null;
+ if(array.length === 1) return array;
+ const middleOfArray = Math.floor(array.length / 2);
+ for(let i = 0; i < middleOfArray; i++){
+ let front = array[i];
+ let back = array[(array.length - 1) - i];
+
+ array[(array.length - 1) - i] = front;
+ array[i] = back;
+ }
+ return array;
+}
+
+module.exports = reverseAnArray;
diff --git a/code-challenges/findSumOfInts/findSumOfInts.js b/code-challenges/findSumOfInts/findSumOfInts.js
new file mode 100644
index 0000000..69e3970
--- /dev/null
+++ b/code-challenges/findSumOfInts/findSumOfInts.js
@@ -0,0 +1,24 @@
+'use strict';
+
+/*
+Problem Domain: Given an array of integers and a value, find a pair of integers in the array that add to that value.
+
+*/
+
+function findSumOfInts(array, key){
+ if(!array || !key) return null;
+ if(typeof key !== 'number' || typeof array !== 'object') return null;
+ if(array.length < 2) return null;
+ const hashMap = new Map();
+ for(let i = 0; i < array.length; i++){
+ hashMap.set(array[i]);
+ }
+ for(let j = 0; j < array.length; j++){
+ let difference = key - array[j];
+ if(hashMap.has(difference)){
+ return [array[j], difference];
+ }
+ }
+}
+
+module.exports = findSumOfInts;
diff --git a/code-challenges/findTreeIntersection/findTreeIntersection.js b/code-challenges/findTreeIntersection/findTreeIntersection.js
new file mode 100644
index 0000000..a6c1f85
--- /dev/null
+++ b/code-challenges/findTreeIntersection/findTreeIntersection.js
@@ -0,0 +1,53 @@
+'use strict';
+
+/**
+ * Returns a set contains the common values between two binary trees
+ *
+ * Complexity:
+ * Time: O(n)
+ * Space: O(n)
+ *
+ * @param {Binary Tree} treeOne
+ * @param {Binary Tree} treeTwo
+ * @returns {Set | null} : set containing common values between two binary trees
+ */
+module.exports = (treeOne, treeTwo) => {
+ if (!treeOne || !treeTwo || !treeOne.root || !treeTwo.root) return null;
+ const valueSet = treeAsSet(treeOne.root);
+ return commonValueSet(treeTwo.root, valueSet);
+};
+
+/**
+ * Recursive function that takes in a binary tree node and
+ * returns set containing all the unique values in a set.
+ *
+ * @param {Binary Tree Node} treeNode
+ * @param {Set | undefined} [set=new Set()]
+ * @returns {Set | null} : set of unique values in binary tree
+ */
+function treeAsSet(treeNode, set = new Set()) {
+ if (!treeNode) return null;
+ set.add(treeNode.value);
+ treeAsSet(treeNode.left, set);
+ treeAsSet(treeNode.right, set);
+ return set;
+}
+
+/**
+ * Recursive function that takes in a binary tree node, a set and
+ * returns a set of the common values between the tree and the set.
+ *
+ * @param {Binary Tree Node} treeNode
+ * @param {Set} valueSet
+ * @param {Set | undefined} [set=new Set()]
+ * @returns {Set | null} : set of common values
+ */
+function commonValueSet(treeNode, valueSet, set = new Set()) {
+ if (!treeNode) return null;
+ if (valueSet.has(treeNode.value)) {
+ set.add(treeNode.value);
+ }
+ commonValueSet(treeNode.left, valueSet, set);
+ commonValueSet(treeNode.right, valueSet, set);
+ return set;
+}
diff --git a/code-challenges/findTreePath/findTreePath.js b/code-challenges/findTreePath/findTreePath.js
new file mode 100644
index 0000000..98c2171
--- /dev/null
+++ b/code-challenges/findTreePath/findTreePath.js
@@ -0,0 +1,27 @@
+'use strict';
+const LinkedList = require('../linked-list/insert-include-print.js');
+
+function findTreePath(node, start, end, LLpath = new LinkedList(), foundStart = false, foundEnd = false){
+ if(!node || !start || !end) return null;
+ if(node){
+ if(node.value === start){
+ foundStart = true;
+ }
+ if(foundStart){
+ LLpath.insert(node.value);
+ if(node.value === end){
+ foundEnd = true;
+ return LLpath;
+ }
+ }
+ if(node.left){
+ findTreePath(node.left, start, end, LLpath, foundStart, foundEnd);
+ }
+ if(node.right){
+ findTreePath(node.right, start, end, LLpath, foundStart, foundEnd);
+ }
+ }
+ return LLpath;
+}
+
+module.exports = findTreePath;
diff --git a/code-challenges/hashtables/hashtables.js b/code-challenges/hashtables/hashtables.js
new file mode 100644
index 0000000..eeedeac
--- /dev/null
+++ b/code-challenges/hashtables/hashtables.js
@@ -0,0 +1,56 @@
+'use strict';
+
+/*
+
+add: takes in both the key and value. This method should hash the key, and add the key and value pair to the table, handling collisions as needed.
+get: takes in the key and returns the value from the table.
+contains: takes in the key and returns a boolean, indicating if the key exists in the table already.
+hash: takes in an arbitrary key and returns an index in the collection.
+
+*/
+
+class HashTable{
+ constructor(length){
+ this.LENGTH = length || 100;
+ this.data = new Array(this.LENGTH);
+ for(let i = 0; i < this.LENGTH; i++){
+ this.data[i] = {};
+ }
+ }
+
+ _stringSum(key){
+ return key.split('').reduce((accumulator, current) => {
+ current = current.charCodeAt(0);
+ return accumulator += current;
+ },0);
+ }
+
+ hash(key){
+ if(typeof key !== 'string' && typeof key !== 'number') return null;
+
+ let convertedKey;
+ if(typeof key === 'string'){
+ convertedKey = this._stringSum(key);
+ }else{
+ convertedKey = key;
+ }
+ return convertedKey * 599 % (this.LENGTH - 1);
+ }
+
+ get(key){
+ let index = this.hash(key);
+ return this.data[index][key] ? this.data[index][key] : null;
+ }
+
+ contains(key){
+ let index = this.hash(key);
+ return !!this.data[index][key];
+ }
+
+ add(key, value){
+ const index = this.hash(key);
+ return Object.assign(this.data[index], {[key]: value})[key];
+ }
+}
+
+module.exports = HashTable;