Skip to content

Feat/add exercises solutions #67

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

Merged
merged 9 commits into from
Aug 22, 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
15 changes: 9 additions & 6 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{
"peacock.color": "#f9e64f",
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#fbed80",
"activityBar.activeBorder": "#06b9a5",
"activityBar.background": "#fbed80",
"activityBar.foreground": "#15202b",
"activityBar.inactiveForeground": "#15202b99",
"activityBarBadge.background": "#06b9a5",
"activityBarBadge.foreground": "#15202b",
"titleBar.activeBackground": "#f9e64f",
"titleBar.inactiveBackground": "#f9e64f99",
"titleBar.activeForeground": "#15202b",
"titleBar.inactiveForeground": "#15202b99",
"statusBar.background": "#f9e64f",
"statusBar.foreground": "#15202b",
"statusBarItem.hoverBackground": "#f7df1e",
"statusBar.foreground": "#15202b"
"titleBar.activeBackground": "#f9e64f",
"titleBar.activeForeground": "#15202b",
"titleBar.inactiveBackground": "#f9e64f99",
"titleBar.inactiveForeground": "#15202b99"
},
"peacock.color": "#f9e64f"
"peacock.remoteColor": "#f9e64f"
}
3 changes: 1 addition & 2 deletions book/A-time-complexity-cheatsheet.asc
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[appendix]
[[a-time-complexity-cheatsheet]]
== Cheatsheet
== Cheatsheet [[a-time-complexity-cheatsheet]]

This section summerize what we are going to cover in the rest of this book.

Expand Down
6 changes: 2 additions & 4 deletions book/B-self-balancing-binary-search-trees.asc
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[appendix]
[[b-self-balancing-binary-search-trees]]
== Self-balancing Binary Search Trees
== Self-balancing Binary Search Trees [[b-self-balancing-binary-search-trees]]

Binary Search Trees (BST) are an excellent data structure to find elements very fast _O(log n)_.
However, when the BST branches have different branch sizes, then the performance suffers.
Expand Down Expand Up @@ -28,8 +27,7 @@ As you might notice, we balanced the tree in the example by doing a rotation.
To be more specific we rotated node `1` to the left to balance the tree.
Let's examine all the possible rotation we can do to balance a tree.

[[tree-rotations]]
=== Tree Rotations
=== Tree Rotations [[tree-rotations]]
(((Tree Rotations)))
We can do single rotations left and right and also we can do double rotations.
Let's go one by one.
Expand Down
5 changes: 2 additions & 3 deletions book/C-AVL-tree.asc
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[appendix]
[[c-avl-tree]]
== AVL Tree
== AVL Tree [[c-avl-tree]]
(((AVL Tree)))
(((Tree, AVL)))
AVL Tree is named after their inventors (**A**delson-**V**elsky and **L**andis).
Expand Down Expand Up @@ -60,4 +59,4 @@ include::../src/data-structures/trees/avl-tree.js[tag=balance]
The first thing we do is to see if one subtree is longer than the other.
If so, then we check the children balance to determine if need a single or double rotation and in which direction.

You can review <<b-self-balancing-binary-search-trees#tree-rotations>> in case you want a refresher.
You can review <<tree-rotations>> in case you want a refresher.
96 changes: 96 additions & 0 deletions book/D-interview-questions-solutions.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
[appendix]
[[d-interview-questions-solutions]]
== Interview Questions Solutions
(((Interview Questions Solutions)))

=== Solutions for Array Questions
(((Interview Questions Solutions, Arrays)))

:leveloffset: -1

[#array-q-max-subarray]
include::content/part02/array.asc[tag=array-q-max-subarray]

The first step is making sure we understand the problem well. Let's do basic examples:

----
A = [-5, 6, 9, -8]
B = [-1, 6, -3, 8]
----

What's the subarray with the maximum sum? For A, it will be `[6, 9]` and for B, it will be `[6, -3, 8]`.

We could generate all possible subarrays, add them up, and then pick the max number.

[source, javascript]
----
include::interview-questions/max-subarray.js[tag=maxSubArrayBrute1]
----

This code is simple to understand; however, not very efficient. The runtime is `O(n^3)`.

If you noticed we adding up the numbers from `i` to `j` on each cycle. But, we can optimize this. We can keep a local variable and add the new number to it. That way, we don't have to revisit previous numbers.

[source, javascript]
----
include::interview-questions/max-subarray.js[tag=maxSubArrayBrute2]
----

The runtime is much better: `O(n)`. Can we still do better?

We can use a greedy approach, where do one pass through the array. We only add the numbers if their sum is larger than just taking the current element.

[source, javascript]
----
include::interview-questions/max-subarray.js[tag=description]
include::interview-questions/max-subarray.js[tag=solution]
----

The runtime is `O(n)` and a space complexity of `O(1)`.




[#array-q-buy-sell-stock]
include::content/part02/array.asc[tag=array-q-buy-sell-stock]

There are multiple examples that we can simulate: bear markets (when prices are going down), bullish markets (when prices are going up), and zig-zag markets (when prices are going up and down).

[source, javascript]
----
// zig-zag market
maxProfit([5, 10, 5, 10]); // => 5
// bullish market
maxProfit([1, 2, 3]); // => 2
// bearish market
maxProfit([3, 2, 1]); // => 0
----

During the bearish markets, the profit will always be 0. Since if you buy, we are only going to lose.

We can do a brute force solution doing all combinations:

[source, javascript]
----
include::interview-questions/buy-sell-stock.js[tag=maxProfitBrute1]
----

The runtime for this solution is `O(n^2)`.

A better solution is to eliminate the 2nd for loop and only do one pass.

Algorithm:

- Do one pass through all the prices
- Keep track of the minimum price seen so far.
- calculate `profit = currentPrice - minPriceSoFar`
- Keep track of the maximun profit seen so far.
- Return maxProfit.

[source, javascript]
----
include::interview-questions/buy-sell-stock.js[tag=description]
include::interview-questions/buy-sell-stock.js[tag=solution]
----

The runtime is `O(n)` and a space complexity of `O(1)`.
35 changes: 0 additions & 35 deletions book/ch02-git-basics-chapter.asc

This file was deleted.

2 changes: 1 addition & 1 deletion book/config
2 changes: 1 addition & 1 deletion book/content/part02/array-vs-list-vs-queue-vs-stack.asc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ In this part of the book, we explored the most used linear data structures such
|===
.2+.^s| Data Structure 2+^s| Searching By 3+^s| Inserting at the 3+^s| Deleting from .2+.^s| Space
^|_Index/Key_ ^|_Value_ ^|_beginning_ ^|_middle_ ^|_end_ ^|_beginning_ ^|_middle_ ^|_end_
| <<part02-linear-data-structures#array>> ^|O(1) ^|O(n) ^|O(n) ^|O(n) ^|O(1) ^|O(n) ^|O(n) ^|O(1) ^|O(n)
| <<array-chap>> ^|O(1) ^|O(n) ^|O(n) ^|O(n) ^|O(1) ^|O(n) ^|O(n) ^|O(1) ^|O(n)
| <<part02-linear-data-structures#singly-linked-list>> ^|O(n) ^|O(n) ^|O(1) ^|O(n) ^|*O(n)* ^|O(1) ^|O(n) ^|*O(n)* ^|O(n)
| <<part02-linear-data-structures#doubly-linked-list>> ^|O(n) ^|O(n) ^|O(1) ^|O(n) ^|*O(1)* ^|O(1) ^|O(n) ^|*O(1)* ^|O(n)
| <<part02-linear-data-structures#stack>> ^|- ^|- ^|- ^|- ^|O(1) ^|- ^|- ^|O(1) ^|O(n)
Expand Down
56 changes: 24 additions & 32 deletions book/content/part02/array.asc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ifndef::imagesdir[]
endif::[]

[[array]]
=== Array
=== Array [[array-chap]]
(((Array)))
(((Data Structures, Linear, Array)))
Arrays are one of the most used data structures. You probably have used it a lot but are you aware of the runtimes of `splice`, `shift`, `indexOf` and other operations? In this chapter, we are going deeper into the most common operations and their runtimes.
Expand All @@ -17,7 +17,8 @@ TIP: Strings are a collection of Unicode characters and most of the array concep

.Fixed vs. Dynamic Size Arrays
****
Some programming languages have fixed size arrays like Java and C++. Fixed size arrays might be a hassle when your collection gets full, and you have to create a new one with a bigger size. For that, those programming languages also have built-in dynamic arrays: we have `vector` in C++ and `ArrayList` in Java. Dynamic programming languages like JavaScript, Ruby, and Python use dynamic arrays by default.
Some programming languages have fixed size arrays like Java and {cpp}.
Fixed size arrays might be a hassle when your collection gets full, and you have to create a new one with a bigger size. For that, those programming languages also have built-in dynamic arrays: we have `vector` in {cpp} and `ArrayList` in Java. Dynamic programming languages like JavaScript, Ruby, and Python use dynamic arrays by default.
****

Arrays look like this:
Expand Down Expand Up @@ -275,46 +276,37 @@ To sum up, the time complexity of an array is:
|===
//end::table

==== Array Exercises
==== Interview Questions
(((Interview Questions, Arrays)))

1) Implement an efficient algorithm that rotate an array `a` an `k` number of times.
// tag::array-q-max-subarray[]
===== Max Subarray

Given an array of integers, find the maximum sum of consecutive elements (subarray).
// end::array-q-max-subarray[]

[source, javascript]
----
/**
* Rotate an array left by k number of times.
*
* @example
* rotateLeft([1,2,3], 1); // [2,3,1]
* rotateLeft([1,2,3,4,5], 4); // [5,1,2,3,4]
*
* rotateLeft(Array(1e6).fill(1), 1e4); // <scale testing>
*
* @param a - The array
* @param k - The number of times the array is rotated
*/
function rotateLeft(a, k) {
// write you code and test with examples
include::../../interview-questions/max-subarray.js[tag=description]
// write you code here
}
----

_Solution: <<array-q-max-subarray>>_

// tag::array-q-buy-sell-stock[]
===== Best Time to Buy and Sell an Stock

2) Implement an algorithm that takes two arrays of numbers and return a new array with the sum.
You are given an array of integers. Each value represents the closing value of the stock on that day. You are only given one chance to buy and then sell. What's the maximun profit you can obtain? (Note: you have to buy first and then sell)
// end::array-q-buy-sell-stock[]

[source, javascript]
----
/**
* Return the sum of two arrays as a new array.
*
* @example
* sum([1,2,3], [1,1,1]); // [2,3,4]
* sum([1], [9,9,9]); // [1,0,0,0]
*
* @param {number[]} a - Array of numbers.
* @param {number[]} b - Array of numbers.
* @returns {number[]} the sum array.
*/
function sum(a, b) {
// write you code and test with examples
include::../../interview-questions/buy-sell-stock.js[tag=description]
// write you code here
}
----

_Solution: <<array-q-buy-sell-stock>>_

// https://leetcode.com/problemset/algorithms/?topicSlugs=array
2 changes: 1 addition & 1 deletion book/content/part03/map.asc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ In short, you set `key`/`value` pair and then you can get the `value` using the
The attractive part of Maps is that they are very performant usually *O(1)* or *O(log n)* depending on the implementation. We can implement the maps using two different underlying data structures:

* *HashMap*: it’s a map implementation using an *array* and a *hash function*. The job of the hash function is to convert the `key` into an index that maps to the `value`. Optimized HashMap can have an average runtime of *O(1)*.
* *TreeMap*: it’s a map implementation that uses a self-balanced Binary Search Tree (like <<c-avl-tree#>>). The BST nodes store the key, and the value and nodes are sorted by key guaranteeing an *O(log n)* look up.
* *TreeMap*: it’s a map implementation that uses a self-balanced Binary Search Tree (like <<c-avl-tree>>). The BST nodes store the key, and the value and nodes are sorted by key guaranteeing an *O(log n)* look up.

<<<
include::hashmap.asc[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In this section, we learned about Graphs applications, properties and how we can
.2+.^s| Data Structure 2+^s| Searching By .2+^.^s| Insert .2+^.^s| Delete .2+^.^s| Space Complexity
^|_Index/Key_ ^|_Value_
| <<part03-graph-data-structures#bst, BST (unbalanced)>> ^|- ^|O(n) ^|O(n) ^|O(n) ^|O(n)
| <<b-self-balancing-binary-search-trees#, BST (balanced)>> ^|- ^|O(log n) ^|O(log n) ^|O(log n) ^|O(n)
| <<b-self-balancing-binary-search-trees, BST (balanced)>> ^|- ^|O(log n) ^|O(log n) ^|O(log n) ^|O(n)
| Hash Map (naïve) ^|O(n) ^|O(n) ^|O(n) ^|O(n) ^|O(n)
| <<part03-graph-data-structures#hashmap, HashMap>> (optimized) ^|O(1) ^|O(n) ^|O(1)* ^|O(1) ^|O(n)
| <<part03-graph-data-structures#treemap, TreeMap>> (Red-Black Tree) ^|O(log n) ^|O(n) ^|O(log n) ^|O(log n) ^|O(n)
Expand Down
4 changes: 2 additions & 2 deletions book/content/preface.asc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

=== What is in this book?

_{doctitle}_ is a book that can be read from cover to cover, where each section builds on top of the previous one. Also, it can be used as a reference manual where developers can refresh specific topics before an interview or look for ideas to solve a problem optimally. (Check out the <<a-time-complexity-cheatsheet#,Time Complexity Cheatsheet>> and <<index#, topical index>>)
_{doctitle}_ is a book that can be read from cover to cover, where each section builds on top of the previous one. Also, it can be used as a reference manual where developers can refresh specific topics before an interview or look for ideas to solve a problem optimally. (Check out the <<a-time-complexity-cheatsheet,Time Complexity Cheatsheet>> and <<index, topical index>>)

This publication is designed to be concise, intending to serve software developers looking to get a firm conceptual understanding of data structures in a quick yet in-depth fashion. After reading this book, the reader should have a fundamental knowledge of algorithms, including when and where to apply it, what are the trade-offs of using one data structure over the other. The reader will then be able to make intelligent decisions about algorithms and data structures in their projects.

Expand Down Expand Up @@ -82,4 +82,4 @@ Measurement is the first step that leads to control and eventually to improvemen

Your feedback is very welcome and valuable. Let us know what your thoughts about this book — what you like or ideas to make it better.

To send us feedback, e-mail us at [email protected], send a tweet to https://twitter.com/iAmAdrianMejia[@iAmAdrianMejia], or using the hash tags `#dsaJS`, `#javascript` and `#algorithms`.
To send us feedback, e-mail us at [email protected], send a tweet to https://twitter.com/iAmAdrianMejia[@iAmAdrianMejia], or using the hash tag `#dsaJS`.
3 changes: 1 addition & 2 deletions book/index.asc
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
[index]
[[index]]
== Index
== Index [[index]]

ifndef::backend-pdf[Topical index only available on the PDF version.]
36 changes: 36 additions & 0 deletions book/interview-questions/buy-sell-stock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// tag::description[]
/**
* Find the max profit from buying and selling a stock given their daily prices.
* @examples
* maxProfit([5, 10, 5, 10]); // => 5
* maxProfit([1, 2, 3]); // => 2
* maxProfit([3, 2, 1]); // => 0
* @param {number[]} prices - Array with daily stock prices
*/
function maxProfit(prices) {
// end::description[]
// tag::solution[]
let max = 0;
let local = Infinity;
for (let i = 0; i < prices.length; i++) {
local = Math.min(local, prices[i]);
max = Math.max(max, prices[i] - local);
}
return max;
}
// end::solution[]

// tag::maxProfitBrute1[]
function maxProfitBrute1(prices) {
let max = 0;
for (let i = 0; i < prices.length; i++) {
for (let j = i + 1; j < prices.length; j++) {
max = Math.max(max, prices[j] - prices[i]);
}
}
return max;
}
// end::maxProfitBrute1[]


module.exports = { maxProfitBrute1, maxProfit };
19 changes: 19 additions & 0 deletions book/interview-questions/buy-sell-stock.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { maxProfitBrute1, maxProfit } = require('./buy-sell-stock');

describe('Best Time to Buy and Sell Stocks', () => {
[maxProfitBrute1, maxProfit].forEach((fn) => {
describe(`with ${fn.name}`, () => {
it('should work with bullish markets', () => {
expect(fn([1, 2, 3])).toEqual(2);
});

it('should work with bearish markets', () => {
expect(fn([3, 2, 1])).toEqual(0);
});

it('should work with zig-zag markets', () => {
expect(fn([5, 10, 5, 10, 5, 10, 5, 10])).toEqual(5);
});
});
});
});
Loading