Skip to content
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
16 changes: 16 additions & 0 deletions .nycrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"require": [
"babel-register",
"babel-polyfill"
],
"sourceMap": false,
"instrument": false,
"lines": 99,
"statements": 99,
"functions": 99,
"branches": 99,
"reporter": [
"lcov",
"text"
]
}
10 changes: 1 addition & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,10 @@
"license": "MIT",
"scripts": {
"lint": "eslint src",
"test": "npm run lint && cross-env NODE_ENV=test nyc mocha src/**/*-test.js --compilers js:babel-register --require babel-polyfill",
"test": "npm run lint && cross-env NODE_ENV=test nyc mocha src/**/*-test.js",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"release": "node ./release.js"
},
"nyc": {
"sourceMap": false,
"instrument": false,
"lines": 99,
"statements": 99,
"functions": 99,
"branches": 99
},
"devDependencies": {
"babel": "^6.23.0",
"babel-core": "^6.26.0",
Expand Down
10 changes: 10 additions & 0 deletions src/common/tree-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Definition for a binary tree node.
*/
export default class TreeNode {
constructor(val) {
this.val = val;
this.left = null;
this.right = null;
}
}
32 changes: 32 additions & 0 deletions src/tree/binary-tree-inorder-traversal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Given a binary tree, return the inorder traversal of its nodes' values.
*
* For example:
* Given binary tree [1,null,2,3],
* 1
* \
* 2
* /
* 3
* return [1,3,2].
*
* Note: Recursive solution is trivial, could you do it iteratively?
*/
const inorderTraversal = root => {
const res = [];

const helper = (root, res) => {
if (!root) {
return;
}

helper(root.left, res);
res.push(root.val);
helper(root.right, res);
};

helper(root, res);
return res;
};

export default inorderTraversal;
112 changes: 112 additions & 0 deletions src/utils/__tests__/tree-util-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { assert } from 'chai';
import TreeNode from '../../common/tree-node';
import { serializeTree, deserializeTree } from '../tree-util';

/**
* 1
* / \
* 2 3
*/
const tree1 = () => {
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
return root;
};

/**
* 1
* \
* 2
*/
const tree2 = () => {
const root = new TreeNode(1);
root.right = new TreeNode(2);
return root;
};

/**
* 1
* \
* 2
* / \
* 3 4
*/
const tree3 = () => {
const root = new TreeNode(1);
root.right = new TreeNode(2);
root.right.left = new TreeNode(3);
root.right.right = new TreeNode(4);
return root;
};

/**
* 1
* \
* 2
* /
* 3
*/
const tree4 = () => {
const root = new TreeNode(1);
root.right = new TreeNode(2);
root.right.left = new TreeNode(3);
return root;
};

/**
* 1
* /
* 2
* /
* 3
*/
const tree5 = () => {
const root = new TreeNode(1);
root.left = new TreeNode(2);
root.left.left = new TreeNode(3);
return root;
};

describe('Tree Util', () => {
describe('Serialize', () => {
const testCases = [
[null, null],
[tree1(), '[1,2,3]'],
[tree2(), '[1,null,2]'],
[tree3(), '[1,null,2,3,4]'],
[tree4(), '[1,null,2,3]'],
[tree5(), '[1,2,null,3]'],
];

testCases.map((testCase, index) => {
it(`should serialize the tree ${index}: ${testCase[1]}`, () => {
const root = testCase[0];
const expected = testCase[1];
const actual = serializeTree(root);
assert.equal(actual, expected);
});
});
});

describe('deserialize', () => {
const testCases = [
[null],
['bad input', null],
['[1,2,3]'],
['[1,null,2]'],
['[1,null,2,3,4]'],
['[1,null,2,3]'],
['[1,2,null,3]'],
];

testCases.map((testCase, index) => {
it(`should deserialize the tree ${index}: ${testCase[0]}`, () => {
const input = testCase[0];
const expected = testCase.length === 1 ? testCase[0] : testCase[1];
const actual = serializeTree(deserializeTree(input));
assert.equal(actual, expected);
});
});
});
});
82 changes: 82 additions & 0 deletions src/utils/tree-util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import TreeNode from '../common/tree-node';

/**
* Encodes a tree to a single string.
*
* @param {TreeNode} root
* @return {string}
*/
const serializeTree = root => {
if (!root) {
return null;
}

let data = [];

// Level-order traversal
const queue = [root];
while (queue.length > 0) {
const node = queue.shift();

if (node) {
data.push(node.val);
queue.push(node.left);
queue.push(node.right);
} else {
data.push(null);
}
}

// Clean up the trailing nulls in data
while (data.length > 0 && data[data.length - 1] === null) {
data.pop();
}

return JSON.stringify(data);
};

/**
* Decodes your encoded data to tree
*
* @param {string} str
* @return {TreeNode}
*/
const deserializeTree = str => {
let data;

// Sanity checks
try {
data = JSON.parse(str);
} catch (e) {
return null;
}
if (!Array.isArray(data) || data.length === 0) {
return null;
}

const root = new TreeNode(data.shift());
const queue = [root];

while (data.length > 0) {
const node = queue.shift();

// Left node
let val = data.shift();
if (typeof val !== 'undefined' && val !== null) {
node.left = new TreeNode(val);
queue.push(node.left);
}

// Right node
val = data.shift();
if (typeof val !== 'undefined' && val !== null) {
node.right = new TreeNode(val);
queue.push(node.right);
}
}

return root;
};

export { serializeTree };
export { deserializeTree };