From 70ec623cbff88eb73e45506c396403acfeb6d404 Mon Sep 17 00:00:00 2001
From: Oleksii Trekhleb <trehleb@gmail.com>
Date: Sat, 11 Aug 2018 15:58:19 +0300
Subject: [PATCH 1/2] Add ComplexNumber.

---
 README.md                                     |   1 +
 .../math/complex-number/ComplexNumber.js      |  73 +++++++
 src/algorithms/math/complex-number/README.md  | 193 ++++++++++++++++++
 .../__test__/ComplexNumber.test.js            | 113 ++++++++++
 4 files changed, 380 insertions(+)
 create mode 100644 src/algorithms/math/complex-number/ComplexNumber.js
 create mode 100644 src/algorithms/math/complex-number/README.md
 create mode 100644 src/algorithms/math/complex-number/__test__/ComplexNumber.test.js

diff --git a/README.md b/README.md
index 27790cfec9..2dc39d8d44 100644
--- a/README.md
+++ b/README.md
@@ -68,6 +68,7 @@ a set of rules that precisely define a sequence of operations.
   * `B` [Sieve of Eratosthenes](src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit
   * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - check if the number is power of two (naive and bitwise algorithms)
   * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle)
+  * `B` [Complex Number](src/algorithms/math/complex-number) - complex numbers and basic operations with them
   * `A` [Integer Partition](src/algorithms/math/integer-partition)
   * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons
 * **Sets**
diff --git a/src/algorithms/math/complex-number/ComplexNumber.js b/src/algorithms/math/complex-number/ComplexNumber.js
new file mode 100644
index 0000000000..61da97442d
--- /dev/null
+++ b/src/algorithms/math/complex-number/ComplexNumber.js
@@ -0,0 +1,73 @@
+export default class ComplexNumber {
+  /**
+   * @param {number} [real]
+   * @param {number} [imaginary]
+   */
+  constructor({ real = 0, imaginary = 0 } = {}) {
+    this.real = real;
+    this.imaginary = imaginary;
+  }
+
+  /**
+   * @param {ComplexNumber} addend
+   * @return {ComplexNumber}
+   */
+  add(addend) {
+    return new ComplexNumber({
+      real: this.real + addend.real,
+      imaginary: this.imaginary + addend.imaginary,
+    });
+  }
+
+  /**
+   * @param {ComplexNumber} subtrahend
+   * @return {ComplexNumber}
+   */
+  subtract(subtrahend) {
+    return new ComplexNumber({
+      real: this.real - subtrahend.real,
+      imaginary: this.imaginary - subtrahend.imaginary,
+    });
+  }
+
+  /**
+   * @param {ComplexNumber} multiplicand
+   * @return {ComplexNumber}
+   */
+  multiply(multiplicand) {
+    return new ComplexNumber({
+      real: this.real * multiplicand.real - this.imaginary * multiplicand.imaginary,
+      imaginary: this.real * multiplicand.imaginary + this.imaginary * multiplicand.real,
+    });
+  }
+
+  /**
+   * @param {ComplexNumber} divider
+   * @return {ComplexNumber}
+   */
+  divide(divider) {
+    // Get divider conjugate.
+    const dividerConjugate = this.conjugate(divider);
+
+    // Multiply dividend by divider's conjugate.
+    const finalDivident = this.multiply(dividerConjugate);
+
+    // Calculating final divider using formula (a + bi)(a − bi) = a^2 + b^2
+    const finalDivider = (divider.real ** 2) + (divider.imaginary ** 2);
+
+    return new ComplexNumber({
+      real: finalDivident.real / finalDivider,
+      imaginary: finalDivident.imaginary / finalDivider,
+    });
+  }
+
+  /**
+   * @param {ComplexNumber} complexNumber
+   */
+  conjugate(complexNumber) {
+    return new ComplexNumber({
+      real: complexNumber.real,
+      imaginary: -1 * complexNumber.imaginary,
+    });
+  }
+}
diff --git a/src/algorithms/math/complex-number/README.md b/src/algorithms/math/complex-number/README.md
new file mode 100644
index 0000000000..ec6b4970a0
--- /dev/null
+++ b/src/algorithms/math/complex-number/README.md
@@ -0,0 +1,193 @@
+# Complex Number
+
+A **complex number** is a number that can be expressed in the 
+form `a + b * i`, where `a` and `b` are real numbers, and `i` is a solution of
+the equation `x^2 = −1`. Because no *real number* satisfies this 
+equation, `i` is called an *imaginary number*. For the complex 
+number `a + b * i`, `a` is called the *real part*, and `b` is called 
+the *imaginary part*.
+
+![Complex Number](https://www.mathsisfun.com/numbers/images/complex-example.svg)
+
+A Complex Number is a combination of a Real Number and an Imaginary Number:
+
+![Complex Number](https://www.mathsisfun.com/numbers/images/complex-number.svg)
+
+Geometrically, complex numbers extend the concept of the one-dimensional number 
+line to the *two-dimensional complex plane* by using the horizontal axis for the
+real part and the vertical axis for the imaginary part. The complex 
+number `a + b * i` can be identified with the point `(a, b)` in the complex plane.
+
+A complex number whose real part is zero is said to be *purely imaginary*; the
+points for these numbers lie on the vertical axis of the complex plane. A complex
+number whose imaginary part is zero can be viewed as a *real number*; its point 
+lies on the horizontal axis of the complex plane.
+
+| Complex Number | Real Part | Imaginary Part |     |
+| :------------- | :-------: | :------------: | --- |
+| 3 + 2i         | 3         | 2              |     |
+| 5              | 5         | **0**          | Purely Real |
+| −6i            | **0**     | -6             | Purely Imaginary |
+
+A complex number can be visually represented as a pair of numbers `(a, b)` forming 
+a vector on a diagram called an *Argand diagram*, representing the *complex plane*.
+`Re` is the real axis, `Im` is the imaginary axis, and `i` satisfies `i^2 = −1`.
+
+![Complex Number](https://upload.wikimedia.org/wikipedia/commons/a/af/Complex_number_illustration.svg)
+
+> Complex does not mean complicated. It means the two types of numbers, real and 
+imaginary, together form a complex, just like a building complex (buildings 
+joined together).
+
+## Basic Operations
+
+### Adding
+
+To add two complex numbers we add each part separately:
+
+```text
+(a + b * i) + (c + d * i) = (a + c) + (b + d) * i
+```
+
+**Example**
+
+```text
+(3 + 5i) + (4 − 3i) = (3 + 4) + (5 − 3)i = 7 + 2i
+```
+
+On complex plane the adding operation will look like the following:
+
+![Complex Addition](https://www.mathsisfun.com/algebra/images/complex-plane-vector-add.svg)
+
+### Subtracting
+
+To subtract two complex numbers we subtract each part separately:
+
+```text
+(a + b * i) - (c + d * i) = (a - c) + (b - d) * i
+```
+
+**Example**
+
+```text
+(3 + 5i) - (4 − 3i) = (3 - 4) + (5 + 3)i = -1 + 8i
+```
+
+### Multiplying
+
+To multiply complex numbers each part of the first complex number gets multiplied 
+by each part of the second complex number:
+
+Just use "FOIL", which stands for "**F**irsts, **O**uters, **I**nners, **L**asts" (
+see [Binomial Multiplication](ttps://www.mathsisfun.com/algebra/polynomials-multiplying.html) for
+more details):
+
+![Complex Multiplication](https://www.mathsisfun.com/algebra/images/foil-complex.svg)
+
+- Firsts: `a × c`
+- Outers: `a × di`
+- Inners: `bi × c`
+- Lasts: `bi × di`
+
+In general it looks like this:
+
+```text
+(a + bi)(c + di) = ac + adi + bci + bdi^2
+```
+
+But there is also a quicker way!
+
+Use this rule:
+
+```text
+(a + bi)(c + di) = (ac − bd) + (ad + bc)i
+```
+
+**Example**
+
+```text
+(3 + 2i)(1 + 7i) 
+= 3×1 + 3×7i + 2i×1+ 2i×7i
+= 3 + 21i + 2i + 14i^2
+= 3 + 21i + 2i − 14   (because i^2 = −1)
+= −11 + 23i
+```
+
+```text
+(3 + 2i)(1 + 7i) = (3×1 − 2×7) + (3×7 + 2×1)i = −11 + 23i
+```
+
+### Conjugates
+
+We will need to know about conjugates in a minute!
+
+A conjugate is where we change the sign in the middle like this:
+
+![Complex Conjugate](https://www.mathsisfun.com/numbers/images/complex-conjugate.svg)
+
+A conjugate is often written with a bar over it:
+
+```text
+______
+5 − 3i   =   5 + 3i
+```
+
+On the complex plane the conjugate number will be mirrored against real axes. 
+
+![Complex Conjugate](https://upload.wikimedia.org/wikipedia/commons/6/69/Complex_conjugate_picture.svg)
+
+### Dividing
+
+The conjugate is used to help complex division.
+
+The trick is to *multiply both top and bottom by the conjugate of the bottom*.
+
+**Example**
+
+```text
+2 + 3i
+------
+4 − 5i
+```
+
+Multiply top and bottom by the conjugate of `4 − 5i`:
+
+```text
+  (2 + 3i) * (4 + 5i)   8 + 10i + 12i + 15i^2
+= ------------------- = ----------------------
+  (4 − 5i) * (4 + 5i)   16 + 20i − 20i − 25i^2
+```
+
+Now remember that `i^2 = −1`, so:
+
+```text
+  8 + 10i + 12i − 15    −7 + 22i   −7   22
+= ------------------- = -------- = -- + -- * i
+  16 + 20i − 20i + 25      41      41   41
+
+```
+
+There is a faster way though.
+
+In the previous example, what happened on the bottom was interesting:
+
+```text
+(4 − 5i)(4 + 5i) = 16 + 20i − 20i − 25i
+```
+
+The middle terms `(20i − 20i)` cancel out!	Also `i^2 = −1` so we end up with this:
+
+```text
+(4 − 5i)(4 + 5i) = 4^2 + 5^2
+```
+
+Which is really quite a simple result. The general rule is:
+
+```text
+(a + bi)(a − bi) = a^2 + b^2
+```
+
+## References
+
+- [Wikipedia](https://en.wikipedia.org/wiki/Complex_number)
+- [Math is Fun](https://www.mathsisfun.com/numbers/complex-numbers.html)
diff --git a/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js b/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js
new file mode 100644
index 0000000000..f6d2a6b5ee
--- /dev/null
+++ b/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js
@@ -0,0 +1,113 @@
+import ComplexNumber from '../ComplexNumber';
+
+describe('ComplexNumber', () => {
+  it('should create complex numbers', () => {
+    const complexNumber = new ComplexNumber({ real: 1, imaginary: 2 });
+
+    expect(complexNumber).toBeDefined();
+    expect(complexNumber.real).toBe(1);
+    expect(complexNumber.imaginary).toBe(2);
+
+    const defaultComplexNumber = new ComplexNumber();
+    expect(defaultComplexNumber.real).toBe(0);
+    expect(defaultComplexNumber.imaginary).toBe(0);
+  });
+
+  it('should add complex numbers', () => {
+    const complexNumber1 = new ComplexNumber({ real: 1, imaginary: 2 });
+    const complexNumber2 = new ComplexNumber({ real: 3, imaginary: 8 });
+
+    const complexNumber3 = complexNumber1.add(complexNumber2);
+    const complexNumber4 = complexNumber2.add(complexNumber1);
+
+    expect(complexNumber3.real).toBe(1 + 3);
+    expect(complexNumber3.imaginary).toBe(2 + 8);
+
+    expect(complexNumber4.real).toBe(1 + 3);
+    expect(complexNumber4.imaginary).toBe(2 + 8);
+  });
+
+  it('should add complex and natural numbers', () => {
+    const complexNumber = new ComplexNumber({ real: 1, imaginary: 2 });
+    const realNumber = new ComplexNumber({ real: 3 });
+
+    const complexNumber3 = complexNumber.add(realNumber);
+    const complexNumber4 = realNumber.add(complexNumber);
+
+    expect(complexNumber3.real).toBe(1 + 3);
+    expect(complexNumber3.imaginary).toBe(2);
+
+    expect(complexNumber4.real).toBe(1 + 3);
+    expect(complexNumber4.imaginary).toBe(2);
+  });
+
+  it('should subtract complex numbers', () => {
+    const complexNumber1 = new ComplexNumber({ real: 1, imaginary: 2 });
+    const complexNumber2 = new ComplexNumber({ real: 3, imaginary: 8 });
+
+    const complexNumber3 = complexNumber1.subtract(complexNumber2);
+    const complexNumber4 = complexNumber2.subtract(complexNumber1);
+
+    expect(complexNumber3.real).toBe(1 - 3);
+    expect(complexNumber3.imaginary).toBe(2 - 8);
+
+    expect(complexNumber4.real).toBe(3 - 1);
+    expect(complexNumber4.imaginary).toBe(8 - 2);
+  });
+
+  it('should subtract complex and natural numbers', () => {
+    const complexNumber = new ComplexNumber({ real: 1, imaginary: 2 });
+    const realNumber = new ComplexNumber({ real: 3 });
+
+    const complexNumber3 = complexNumber.subtract(realNumber);
+    const complexNumber4 = realNumber.subtract(complexNumber);
+
+    expect(complexNumber3.real).toBe(1 - 3);
+    expect(complexNumber3.imaginary).toBe(2);
+
+    expect(complexNumber4.real).toBe(3 - 1);
+    expect(complexNumber4.imaginary).toBe(-2);
+  });
+
+  it('should multiply complex numbers', () => {
+    const complexNumber1 = new ComplexNumber({ real: 3, imaginary: 2 });
+    const complexNumber2 = new ComplexNumber({ real: 1, imaginary: 7 });
+
+    const complexNumber3 = complexNumber1.multiply(complexNumber2);
+    const complexNumber4 = complexNumber2.multiply(complexNumber1);
+
+    expect(complexNumber3.real).toBe(-11);
+    expect(complexNumber3.imaginary).toBe(23);
+
+    expect(complexNumber4.real).toBe(-11);
+    expect(complexNumber4.imaginary).toBe(23);
+  });
+
+  it('should multiply complex numbers by themselves', () => {
+    const complexNumber = new ComplexNumber({ real: 1, imaginary: 1 });
+
+    const result = complexNumber.multiply(complexNumber);
+
+    expect(result.real).toBe(0);
+    expect(result.imaginary).toBe(2);
+  });
+
+  it('should calculate i in power of two', () => {
+    const complexNumber = new ComplexNumber({ real: 0, imaginary: 1 });
+
+    const result = complexNumber.multiply(complexNumber);
+
+    expect(result.real).toBe(-1);
+    expect(result.imaginary).toBe(0);
+  });
+
+  it('should divide complex numbers', () => {
+    const complexNumber1 = new ComplexNumber({ real: 2, imaginary: 3 });
+    const complexNumber2 = new ComplexNumber({ real: 4, imaginary: -5 });
+
+    const complexNumber3 = complexNumber1.divide(complexNumber2);
+
+    expect(complexNumber3.real).toBe(-7 / 41);
+    expect(complexNumber3.imaginary).toBe(22 / 41);
+  });
+});

From 5cf8ac25552c295b7b1769e3c8fa342b975d9e1e Mon Sep 17 00:00:00 2001
From: Bruce Feldman <bfeldman@sunriselabs.com>
Date: Fri, 10 Aug 2018 17:12:40 -0400
Subject: [PATCH 2/2] Added Efficient LIS (nlog(n))

---
 .../longestIncreasingSubsequence.test.js      | 36 +++++++++++++++++++
 .../longestIncreasingSubsequence.js           | 28 +++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 src/algorithms/sets/longest-increasing-subsequence/__test__/longestIncreasingSubsequence.test.js
 create mode 100644 src/algorithms/sets/longest-increasing-subsequence/longestIncreasingSubsequence.js

diff --git a/src/algorithms/sets/longest-increasing-subsequence/__test__/longestIncreasingSubsequence.test.js b/src/algorithms/sets/longest-increasing-subsequence/__test__/longestIncreasingSubsequence.test.js
new file mode 100644
index 0000000000..4a444a895a
--- /dev/null
+++ b/src/algorithms/sets/longest-increasing-subsequence/__test__/longestIncreasingSubsequence.test.js
@@ -0,0 +1,36 @@
+import longestIncreasingSubsequence from '../longestIncreasingSubsequence';
+
+describe('LongestIncreasingSubsequence', () => {
+  it('should find longest increasing subsequence length', () => {
+    // Should be:
+    // 9 or
+    // 8 or
+    // 7 or
+    // 6 or
+    // ...
+    expect(longestIncreasingSubsequence([
+      9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+    ])).toBe(1);
+
+    // Should be:
+    // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+    expect(longestIncreasingSubsequence([
+      0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+    ])).toBe(10);
+
+    // Should be:
+    // -1, 0, 2, 3
+    expect(longestIncreasingSubsequence([
+      3, 4, -1, 0, 6, 2, 3,
+    ])).toBe(4);
+
+    // Should be:
+    // 0, 2, 6, 9, 11, 15 or
+    // 0, 4, 6, 9, 11, 15 or
+    // 0, 2, 6, 9, 13, 15 or
+    // 0, 4, 6, 9, 13, 15
+    expect(longestIncreasingSubsequence([
+      0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15,
+    ])).toBe(6);
+  });
+});
diff --git a/src/algorithms/sets/longest-increasing-subsequence/longestIncreasingSubsequence.js b/src/algorithms/sets/longest-increasing-subsequence/longestIncreasingSubsequence.js
new file mode 100644
index 0000000000..88e97accea
--- /dev/null
+++ b/src/algorithms/sets/longest-increasing-subsequence/longestIncreasingSubsequence.js
@@ -0,0 +1,28 @@
+/**
+ * Efficient approach to find longest increasing subsequence.
+ * Complexity: O(n * log(n))
+ *
+ * @param {number[]} sequence
+ * @return {number}
+ */
+export default function LongestIncreasingSubsequence(sequence) {
+  // Retrieves the smallest number greater or equal to val in sorted arr.
+  function upperBound(arr, val) {
+    let lo = 0;
+    let hi = arr.length;
+
+    while (lo < hi) {
+      const mid = lo + Math.floor((hi - lo) / 2);
+      if (arr[mid] < val) {
+        lo = mid + 1;
+      } else {
+        hi = mid;
+      }
+    }
+    return hi;
+  }
+
+  const lis = [];
+  sequence.forEach((val) => { lis[upperBound(lis, val)] = val; });
+  return lis.length;
+}