Add a Divide and Conquer version of the MaxSubArray problem.

This commit is contained in:
Oleksii Trekhleb 2022-02-04 08:56:15 +01:00
parent 819f38f792
commit 82f0b5edf0
8 changed files with 67 additions and 8 deletions

2
.npmrc
View File

@ -1 +1 @@
engine-strict=false engine-strict=true

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v14

View File

@ -207,6 +207,7 @@ algorithm is an abstraction higher than a computer program.
* `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples
* `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions) * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions)
* `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions) * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions)
* `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
* **Dynamic Programming** - build up a solution using previously found sub-solutions * **Dynamic Programming** - build up a solution using previously found sub-solutions
* `B` [Fibonacci Number](src/algorithms/math/fibonacci) * `B` [Fibonacci Number](src/algorithms/math/fibonacci)
* `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
@ -278,6 +279,8 @@ rm -rf ./node_modules
npm i npm i
``` ```
Also make sure that you're using a correct Node version (`>=14.16.0`). If you're using [nvm](https://github.com/nvm-sh/nvm) for Node version management you may run `nvm use` from the root folder of the project and the correct version will be picked up.
**Playground** **Playground**
You may play with data-structures and algorithms in `./src/playground/playground.js` file and write You may play with data-structures and algorithms in `./src/playground/playground.js` file and write

View File

@ -15,6 +15,12 @@ with `0`. For example, for the array of
values `2, 1, 3, 4, 1, 2, 1, 5, 4` the contiguous subarray values `2, 1, 3, 4, 1, 2, 1, 5, 4` the contiguous subarray
with the largest sum is `4, 1, 2, 1`, with sum `6`. with the largest sum is `4, 1, 2, 1`, with sum `6`.
## Solutions
- Brute Force solution `O(n^2)`: [bfMaximumSubarray.js](./bfMaximumSubarray.js)
- Divide and Conquer solution `O(n^2)`: [dcMaximumSubarraySum.js](./dcMaximumSubarraySum.js)
- Dynamic Programming solution `O(n)`: [dpMaximumSubarray.js](./dpMaximumSubarray.js)
## References ## References
- [Wikipedia](https://en.wikipedia.org/wiki/Maximum_subarray_problem) - [Wikipedia](https://en.wikipedia.org/wiki/Maximum_subarray_problem)

View File

@ -1,7 +1,7 @@
import bfMaximumSubarray from '../bfMaximumSubarray'; import bfMaximumSubarray from '../bfMaximumSubarray';
describe('bfMaximumSubarray', () => { describe('bfMaximumSubarray', () => {
it('should find maximum subarray using brute force algorithm', () => { it('should find maximum subarray using the brute force algorithm', () => {
expect(bfMaximumSubarray([])).toEqual([]); expect(bfMaximumSubarray([])).toEqual([]);
expect(bfMaximumSubarray([0, 0])).toEqual([0]); expect(bfMaximumSubarray([0, 0])).toEqual([0]);
expect(bfMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]); expect(bfMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]);

View File

@ -0,0 +1,16 @@
import dcMaximumSubarray from '../dcMaximumSubarraySum';
describe('dcMaximumSubarraySum', () => {
it('should find maximum subarray sum using the divide and conquer algorithm', () => {
expect(dcMaximumSubarray([])).toEqual(-Infinity);
expect(dcMaximumSubarray([0, 0])).toEqual(0);
expect(dcMaximumSubarray([0, 0, 1])).toEqual(1);
expect(dcMaximumSubarray([0, 0, 1, 2])).toEqual(3);
expect(dcMaximumSubarray([0, 0, -1, 2])).toEqual(2);
expect(dcMaximumSubarray([-1, -2, -3, -4, -5])).toEqual(-1);
expect(dcMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual(20);
expect(dcMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual(6);
expect(dcMaximumSubarray([-2, -3, 4, -1, -2, 1, 5, -3])).toEqual(7);
expect(dcMaximumSubarray([1, -3, 2, -5, 7, 6, -1, 4, 11, -23])).toEqual(27);
});
});

View File

@ -1,7 +1,7 @@
import dpMaximumSubarray from '../dpMaximumSubarray'; import dpMaximumSubarray from '../dpMaximumSubarray';
describe('dpMaximumSubarray', () => { describe('dpMaximumSubarray', () => {
it('should find maximum subarray using dynamic programming algorithm', () => { it('should find maximum subarray using the dynamic programming algorithm', () => {
expect(dpMaximumSubarray([])).toEqual([]); expect(dpMaximumSubarray([])).toEqual([]);
expect(dpMaximumSubarray([0, 0])).toEqual([0]); expect(dpMaximumSubarray([0, 0])).toEqual([0]);
expect(dpMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]); expect(dpMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]);

View File

@ -0,0 +1,33 @@
/**
* Divide and Conquer solution.
* Complexity: O(n^2) in case if no memoization applied
*
* @param {Number[]} inputArray
* @return {Number[]}
*/
export default function dcMaximumSubarraySum(inputArray) {
/**
* We are going through the inputArray array and for each element we have two options:
* - to pick
* - not to pick
*
* Also keep in mind, that the maximum sub-array must be contiguous. It means if we picked
* the element, we need to continue picking the next elements or stop counting the max sum.
*
* @param {number} elementIndex - the index of the element we're deciding to pick or not
* @param {boolean} mustPick - to pick or not to pick the element
* @returns {number} - maximum subarray sum that we'll get
*/
function solveRecursively(elementIndex, mustPick) {
if (elementIndex >= inputArray.length) {
return mustPick ? 0 : -Infinity;
}
return Math.max(
// Option #1: Pick the current element, and continue picking next one.
inputArray[elementIndex] + solveRecursively(elementIndex + 1, true),
// Option #2: Don't pick the current element.
mustPick ? 0 : solveRecursively(elementIndex + 1, false),
);
}
return solveRecursively(0, false);
}