From d790a3f8bd515b2e7546ea4e83154e9e2e8ce60b Mon Sep 17 00:00:00 2001 From: alex_p Date: Mon, 31 Oct 2022 11:56:18 +0300 Subject: [PATCH 1/2] algorithm: add UniquePaths2 algo and a test for it --- Dynamic-Programming/UniquePaths2.js | 80 +++++++++++++++++++ .../tests/UniquePaths2.test.js | 19 +++++ 2 files changed, 99 insertions(+) create mode 100644 Dynamic-Programming/UniquePaths2.js create mode 100644 Dynamic-Programming/tests/UniquePaths2.test.js diff --git a/Dynamic-Programming/UniquePaths2.js b/Dynamic-Programming/UniquePaths2.js new file mode 100644 index 0000000000..7fc5ef3f36 --- /dev/null +++ b/Dynamic-Programming/UniquePaths2.js @@ -0,0 +1,80 @@ +/* + * Unique Paths 2 + * + * There is a robot on an `m x n` grid. + * The robot is initially located at the top-left corner + * The robot tries to move to the bottom-right corner. + * The robot can only move either down or right at any point in time. + * + * Given grid with obstacles + * An obstacle and space are marked as 1 or 0 respectively in grid. + * A path that the robot takes cannot include any square that is an obstacle. + * Return the number of possible unique paths that the robot can take to reach the bottom-right corner. + * + * More info: https://leetcode.com/problems/unique-paths-ii/ + */ + +/** + * @description Return 'rows x columns' grid with cells filled by 'filler' + * @param {Number} rows Number of rows in the grid + * @param {Number} columns Number of columns in the grid + * @param {String | Number | Boolean} filler The value to fill cells + * @returns {Object []} + */ +const generateMatrix = (rows, columns, filler = 0) => { + const matrix = [] + for (let i = 0; i < rows; i += 1) { + const submatrix = [] + for (let k = 0; k < columns; k += 1) { + submatrix[k] = filler + } + matrix[i] = submatrix + } + return matrix +} + +/** + * @description Return number of unique paths + * @param {Object []} obstacles Obstacles grid + * @returns {Number} + */ +const uniquePaths2 = (obstacles) => { + if (!(obstacles instanceof Object)) { + throw new Error('Input data must be type of Array') + } + // Create grid for calculating number of unique ways + const rows = obstacles.length + const columns = obstacles[0].length + const grid = generateMatrix(rows, columns) + // Fill the outermost cell with 1 b/c it has + // the only way to reach neighbor + for (let i = 0; i < rows; i += 1) { + // If robot encounters an obstacle in these cells, + // he cannot continue movind in that direction + if (obstacles[i][0]) { + break + } + grid[i][0] = 1 + } + for (let j = 0; j < columns; j += 1) { + if (obstacles[0][j]) { + break + } + grid[0][j] = 1 + } + // Fill the rest of grid by dynamic programming + // using following reccurent formula: + // K[i][j] = K[i - 1][j] + K[i][j - 1] + for (let i = 1; i < rows; i += 1) { + for (let j = 1; j < columns; j += 1) { + if (obstacles[i][j]) { + grid[i][j] = 0 + } else { + grid[i][j] = grid[i - 1][j] + grid[i][j - 1] + } + } + } + return grid[rows - 1][columns - 1] +} + +export { uniquePaths2 } diff --git a/Dynamic-Programming/tests/UniquePaths2.test.js b/Dynamic-Programming/tests/UniquePaths2.test.js new file mode 100644 index 0000000000..c35b1facee --- /dev/null +++ b/Dynamic-Programming/tests/UniquePaths2.test.js @@ -0,0 +1,19 @@ +import { uniquePaths2 } from '../UniquePaths2' + +describe('Unique Paths2', () => { + // Should return number of ways, taken into account the obstacles + test('Case 1: there are obstacles in the way', () => { + expect(uniquePaths2([[0, 0, 0], [0, 1, 0], [0, 0, 0]])).toEqual(2) + expect(uniquePaths2([[0, 0, 0], [0, 1, 0], [0, 0, 0], [1, 0, 0]])).toEqual(3) + }) + // Should return number of all possible ways to reach right-bottom corner + test('Case 2: there are no obstacles in the way', () => { + expect(uniquePaths2([[0, 0, 0], [0, 0, 0], [0, 0, 0]])).toEqual(6) + expect(uniquePaths2([[0, 0, 0], [0, 0, 0]])).toEqual(3) + }) + // Should throw an exception b/c input data has wrong type + test('Case 3: there are wrong type of input data', () => { + expect(() => uniquePaths2('wrong input')).toThrow() + expect(() => uniquePaths2(100)).toThrow() + }) +}) From ae50228fc50ebacef429f90d5320fb4fa2243e3e Mon Sep 17 00:00:00 2001 From: alex_p Date: Mon, 31 Oct 2022 12:12:15 +0300 Subject: [PATCH 2/2] fix: fix inaccuracies and spelling errors --- Dynamic-Programming/UniquePaths2.js | 26 ++++++++----------- .../tests/UniquePaths2.test.js | 6 ++--- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Dynamic-Programming/UniquePaths2.js b/Dynamic-Programming/UniquePaths2.js index 7fc5ef3f36..52bf9d08b2 100644 --- a/Dynamic-Programming/UniquePaths2.js +++ b/Dynamic-Programming/UniquePaths2.js @@ -19,13 +19,13 @@ * @param {Number} rows Number of rows in the grid * @param {Number} columns Number of columns in the grid * @param {String | Number | Boolean} filler The value to fill cells - * @returns {Object []} + * @returns {Array [][]} */ const generateMatrix = (rows, columns, filler = 0) => { const matrix = [] - for (let i = 0; i < rows; i += 1) { + for (let i = 0; i < rows; i++) { const submatrix = [] - for (let k = 0; k < columns; k += 1) { + for (let k = 0; k < columns; k++) { submatrix[k] = filler } matrix[i] = submatrix @@ -35,11 +35,11 @@ const generateMatrix = (rows, columns, filler = 0) => { /** * @description Return number of unique paths - * @param {Object []} obstacles Obstacles grid + * @param {Array [][]} obstacles Obstacles grid * @returns {Number} */ const uniquePaths2 = (obstacles) => { - if (!(obstacles instanceof Object)) { + if (!Array.isArray(obstacles)) { throw new Error('Input data must be type of Array') } // Create grid for calculating number of unique ways @@ -48,15 +48,15 @@ const uniquePaths2 = (obstacles) => { const grid = generateMatrix(rows, columns) // Fill the outermost cell with 1 b/c it has // the only way to reach neighbor - for (let i = 0; i < rows; i += 1) { + for (let i = 0; i < rows; i++) { // If robot encounters an obstacle in these cells, - // he cannot continue movind in that direction + // he cannot continue moving in that direction if (obstacles[i][0]) { break } grid[i][0] = 1 } - for (let j = 0; j < columns; j += 1) { + for (let j = 0; j < columns; j++) { if (obstacles[0][j]) { break } @@ -65,13 +65,9 @@ const uniquePaths2 = (obstacles) => { // Fill the rest of grid by dynamic programming // using following reccurent formula: // K[i][j] = K[i - 1][j] + K[i][j - 1] - for (let i = 1; i < rows; i += 1) { - for (let j = 1; j < columns; j += 1) { - if (obstacles[i][j]) { - grid[i][j] = 0 - } else { - grid[i][j] = grid[i - 1][j] + grid[i][j - 1] - } + for (let i = 1; i < rows; i++) { + for (let j = 1; j < columns; j++) { + grid[i][j] = obstacles[i][j] ? 0 : grid[i - 1][j] + grid[i][j - 1] } } return grid[rows - 1][columns - 1] diff --git a/Dynamic-Programming/tests/UniquePaths2.test.js b/Dynamic-Programming/tests/UniquePaths2.test.js index c35b1facee..e34b9a3303 100644 --- a/Dynamic-Programming/tests/UniquePaths2.test.js +++ b/Dynamic-Programming/tests/UniquePaths2.test.js @@ -2,17 +2,17 @@ import { uniquePaths2 } from '../UniquePaths2' describe('Unique Paths2', () => { // Should return number of ways, taken into account the obstacles - test('Case 1: there are obstacles in the way', () => { + test('There are obstacles in the way', () => { expect(uniquePaths2([[0, 0, 0], [0, 1, 0], [0, 0, 0]])).toEqual(2) expect(uniquePaths2([[0, 0, 0], [0, 1, 0], [0, 0, 0], [1, 0, 0]])).toEqual(3) }) // Should return number of all possible ways to reach right-bottom corner - test('Case 2: there are no obstacles in the way', () => { + test('There are no obstacles in the way', () => { expect(uniquePaths2([[0, 0, 0], [0, 0, 0], [0, 0, 0]])).toEqual(6) expect(uniquePaths2([[0, 0, 0], [0, 0, 0]])).toEqual(3) }) // Should throw an exception b/c input data has wrong type - test('Case 3: there are wrong type of input data', () => { + test('There are wrong type of input data', () => { expect(() => uniquePaths2('wrong input')).toThrow() expect(() => uniquePaths2(100)).toThrow() })