From 82f6544c5aa053ab14a012315feb2406ab2c52ce Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Sun, 18 Aug 2019 17:47:47 +0800 Subject: [PATCH 01/11] added solution for Find Words That Can Be Formed by Characters. --- .../README.md | 7 +++ .../solution.js | 47 +++++++++++++++++++ .../solution.test.js | 19 ++++++++ 3 files changed, 73 insertions(+) create mode 100644 problems/find-words-that-can-be-formed-by-characters/README.md create mode 100644 problems/find-words-that-can-be-formed-by-characters/solution.js create mode 100644 problems/find-words-that-can-be-formed-by-characters/solution.test.js diff --git a/problems/find-words-that-can-be-formed-by-characters/README.md b/problems/find-words-that-can-be-formed-by-characters/README.md new file mode 100644 index 0000000..f4192c1 --- /dev/null +++ b/problems/find-words-that-can-be-formed-by-characters/README.md @@ -0,0 +1,7 @@ +# Find Words That Can Be Formed by Characters + +LeetCode #: 1160 [Link](https://leetcode.com/problems/find-words-that-can-be-formed-by-characters/) + +Difficulty: Easy + +Topics: Array, hash table. diff --git a/problems/find-words-that-can-be-formed-by-characters/solution.js b/problems/find-words-that-can-be-formed-by-characters/solution.js new file mode 100644 index 0000000..3718283 --- /dev/null +++ b/problems/find-words-that-can-be-formed-by-characters/solution.js @@ -0,0 +1,47 @@ +/** + * @param {string[]} words + * @param {string} chars + * @return {number} + */ +const countCharacters = function (words, chars) { + const charMap = new Map() + chars.split('').forEach((c) => { + if (charMap.has(c)) { + charMap.set(c, charMap.get(c) + 1) + } else { + charMap.set(c, 1) + } + }) + + let length = 0 + + for (const word of words) { + let ok = true + const ws = word.split('') + const wMap = new Map() + + for (const w of ws) { + if (wMap.has(w)) { + wMap.set(w, wMap.get(w) + 1) + } else { + wMap.set(w, 1) + } + + if ( + (!charMap.get(w)) || + (wMap.get(w) > charMap.get(w)) + ) { + ok = false + break + } + } + + if (ok) { + length += word.length + } + } + + return length +} + +module.exports = countCharacters diff --git a/problems/find-words-that-can-be-formed-by-characters/solution.test.js b/problems/find-words-that-can-be-formed-by-characters/solution.test.js new file mode 100644 index 0000000..7f2a7f7 --- /dev/null +++ b/problems/find-words-that-can-be-formed-by-characters/solution.test.js @@ -0,0 +1,19 @@ +const countCharacters = require('./solution') + +test('Example 1', () => { + const words = ['cat', 'bt', 'hat', 'tree'] + const chars = 'atach' + + const result = countCharacters(words, chars) + + expect(result).toBe(6) +}) + +test('Example 2', () => { + const words = ['hello', 'world', 'leetcode'] + const chars = 'welldonehoneyr' + + const result = countCharacters(words, chars) + + expect(result).toBe(10) +}) From bd81770a098500803050e6257c48c4aed1410a92 Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Sun, 18 Aug 2019 17:51:11 +0800 Subject: [PATCH 02/11] added solution for Maximum Level Sum of a Binary Tree. --- .../README.md | 7 +++ .../solution.js | 58 +++++++++++++++++++ .../solution.test.js | 11 ++++ 3 files changed, 76 insertions(+) create mode 100644 problems/maximum-level-sum-of-a-binary-tree/README.md create mode 100644 problems/maximum-level-sum-of-a-binary-tree/solution.js create mode 100644 problems/maximum-level-sum-of-a-binary-tree/solution.test.js diff --git a/problems/maximum-level-sum-of-a-binary-tree/README.md b/problems/maximum-level-sum-of-a-binary-tree/README.md new file mode 100644 index 0000000..2b645a4 --- /dev/null +++ b/problems/maximum-level-sum-of-a-binary-tree/README.md @@ -0,0 +1,7 @@ +# Maximum Level Sum of a Binary Tree + +LeetCode #: 1161 [Link](https://leetcode.com/problems/maximum-level-sum-of-a-binary-tree/) + +Difficulty: Medium + +Topic: Binary Tree diff --git a/problems/maximum-level-sum-of-a-binary-tree/solution.js b/problems/maximum-level-sum-of-a-binary-tree/solution.js new file mode 100644 index 0000000..042315c --- /dev/null +++ b/problems/maximum-level-sum-of-a-binary-tree/solution.js @@ -0,0 +1,58 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const maxLevelSum = function (root) { + const map = {} + + const nodeQueue = [root] + let currentLevel = 1 + let currentLevelNodeCount = 1 + let currentLevelSum = 0 + + while (nodeQueue.length > 0) { + const node = nodeQueue.shift() + + if (node !== null) { + currentLevelSum += node.val + + if (node.left) { + nodeQueue.push(node.left) + } + + if (node.right) { + nodeQueue.push(node.right) + } + } + + currentLevelNodeCount -= 1 + + if (currentLevelNodeCount === 0) { + map[currentLevel] = currentLevelSum + + currentLevel += 1 + currentLevelSum = 0 + currentLevelNodeCount = nodeQueue.length + } + } + + let level = 0 + let maxSum = Number.MIN_SAFE_INTEGER + for (const [key, value] of Object.entries(map)) { + if (value > maxSum) { + maxSum = value + level = parseInt(key) + } + } + + return level +} + +module.exports = maxLevelSum diff --git a/problems/maximum-level-sum-of-a-binary-tree/solution.test.js b/problems/maximum-level-sum-of-a-binary-tree/solution.test.js new file mode 100644 index 0000000..c46e804 --- /dev/null +++ b/problems/maximum-level-sum-of-a-binary-tree/solution.test.js @@ -0,0 +1,11 @@ +const leettree = require('leettree') +const maxLevelSum = require('./solution') + +test('Example 1', () => { + const array = [1, 7, 0, 7, -8, null, null] + const root = leettree.deserialize(array) + + const result = maxLevelSum(root) + + expect(result).toBe(2) +}) From a6a72e00d39bd0c8221003ffac3ce33f0d2356a7 Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Sun, 18 Aug 2019 17:53:38 +0800 Subject: [PATCH 03/11] added solution for As Far from Land as Possible. --- .../as-far-from-land-as-possible/README.md | 7 + .../as-far-from-land-as-possible/solution.js | 144 ++++++++++++++++++ .../solution.test.js | 33 ++++ 3 files changed, 184 insertions(+) create mode 100644 problems/as-far-from-land-as-possible/README.md create mode 100644 problems/as-far-from-land-as-possible/solution.js create mode 100644 problems/as-far-from-land-as-possible/solution.test.js diff --git a/problems/as-far-from-land-as-possible/README.md b/problems/as-far-from-land-as-possible/README.md new file mode 100644 index 0000000..a3b4789 --- /dev/null +++ b/problems/as-far-from-land-as-possible/README.md @@ -0,0 +1,7 @@ +# As Far from Land as Possible + +LeetCode #: [1162](https://leetcode.com/problems/as-far-from-land-as-possible/) + +Difficulty: Medium + +Topic: Breadth-First Search, Graph. diff --git a/problems/as-far-from-land-as-possible/solution.js b/problems/as-far-from-land-as-possible/solution.js new file mode 100644 index 0000000..43aaa76 --- /dev/null +++ b/problems/as-far-from-land-as-possible/solution.js @@ -0,0 +1,144 @@ +const createDistances = (grid) => { + const distance = Array.from(grid, (rowEl, rowInd) => { + return Array.from(rowEl, (colEl, colInd) => { + return null + }) + }) + + return distance +} + +const getNextSquares = (distanceGrid, newSquare, squares) => { + if ( + distanceGrid[newSquare.row] && + distanceGrid[newSquare.row][newSquare.col] === null + ) { + squares.push(newSquare) + distanceGrid[newSquare.row][newSquare.col] = -1 + } + + return squares +} + +const calculateDistanceInfo = (distanceGrid, distanceSquares, distanceSumDiffs) => { + const currentDistance = distanceSquares.length - 1 + const squares = distanceSquares[currentDistance] + + // const hrtimeSquares = process.hrtime() + for (const square of squares) { + distanceGrid[square.row][square.col] = currentDistance + } + // const hrtimeSquaresDiff = process.hrtime(hrtimeSquares) + // console.log('hrtimeSquaresDiff: ', hrtimeSquaresDiff[1] / 1000000) + + // const hrtimeNextSquares = process.hrtime() + let nextSquares = [] + for (const square of squares) { + nextSquares = getNextSquares(distanceGrid, { row: square.row - 1, col: square.col, sum: square.row - 1 + square.col, diff: square.row - 1 - square.col }, nextSquares) + nextSquares = getNextSquares(distanceGrid, { row: square.row, col: square.col - 1, sum: square.row + (square.col - 1), diff: square.row - (square.col - 1) }, nextSquares) + nextSquares = getNextSquares(distanceGrid, { row: square.row, col: square.col + 1, sum: square.row + (square.col + 1), diff: square.row - (square.col + 1) }, nextSquares) + nextSquares = getNextSquares(distanceGrid, { row: square.row + 1, col: square.col, sum: square.row + 1 + square.col, diff: square.row + 1 - square.col }, nextSquares) + } + + // const hrtimeNextSquaresDiff = process.hrtime(hrtimeNextSquares) + // console.log('hrtimeNextSquaresDiff: ', hrtimeNextSquaresDiff[1] / 1000000) + + if (nextSquares.length === 0) { + return { + distanceGrid: distanceGrid, + distanceSquares: distanceSquares, + distanceSumDiffs: distanceSumDiffs + } + } + + distanceSquares.push(nextSquares) + + const sumDiffs = nextSquares.reduce( + (acc, cur) => { + acc.minSum = Math.min(acc.minSum, cur.sum) + acc.maxSum = Math.max(acc.maxSum, cur.sum) + acc.minDiff = Math.min(acc.minDiff, cur.diff) + acc.maxDiff = Math.max(acc.maxDiff, cur.diff) + + return acc + }, + { + minSum: Number.MAX_SAFE_INTEGER, + maxSum: Number.MIN_SAFE_INTEGER, + minDiff: Number.MAX_SAFE_INTEGER, + maxDiff: Number.MIN_SAFE_INTEGER + } + ) + + distanceSumDiffs.push(sumDiffs) + + return calculateDistanceInfo(distanceGrid, distanceSquares, distanceSumDiffs) +} + +const getDistanceInfo = (grid, offices) => { + const emptyDistanceGrid = createDistances(grid) + + const distanceOffices = [] + distanceOffices.push(offices) + + const distanceSumDiffs = [] + const sumDiffs = distanceOffices[0].reduce( + (acc, cur) => { + acc.minSum = Math.min(acc.minSum, cur.sum) + acc.maxSum = Math.max(acc.maxSum, cur.sum) + acc.minDiff = Math.min(acc.minDiff, cur.diff) + acc.maxDiff = Math.max(acc.maxDiff, cur.diff) + + return acc + }, + { + minSum: Number.MAX_SAFE_INTEGER, + maxSum: Number.MIN_SAFE_INTEGER, + minDiff: Number.MAX_SAFE_INTEGER, + maxDiff: Number.MIN_SAFE_INTEGER + } + ) + + distanceSumDiffs.push(sumDiffs) + + return calculateDistanceInfo(emptyDistanceGrid, distanceOffices, distanceSumDiffs) +} + +/// ///// + +const maxDistance = (input) => { + const offices = [] + let hasLand = false + let hasWater = false + + for (let i = 0; i < input.length; i++) { + const eli = input[i] + + for (let j = 0; j < eli.length; j++) { + const elj = eli[j] + + if (elj === 1) { + hasLand = true + + offices.push({ + row: i, + col: j + }) + } + + if (elj === 0) { + hasWater = true + } + } + } + + if (!(hasLand && hasWater)) { + return -1 + } + + const distanceInfo = getDistanceInfo(input, offices) + + return distanceInfo.distanceSquares.length - 1 +} + +module.exports = maxDistance diff --git a/problems/as-far-from-land-as-possible/solution.test.js b/problems/as-far-from-land-as-possible/solution.test.js new file mode 100644 index 0000000..050fbe1 --- /dev/null +++ b/problems/as-far-from-land-as-possible/solution.test.js @@ -0,0 +1,33 @@ +const maxDistance = require('./solution') + +test('Example 1', () => { + const input = [[1, 0, 1], [0, 0, 0], [1, 0, 1]] + + const result = maxDistance(input) + + expect(result).toBe(2) +}) + +test('Example 2', () => { + const input = [[1, 0, 0], [0, 0, 0], [0, 0, 0]] + + const result = maxDistance(input) + + expect(result).toBe(4) +}) + +test('All water', () => { + const input = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] + + const result = maxDistance(input) + + expect(result).toBe(-1) +}) + +test('All land', () => { + const input = [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + + const result = maxDistance(input) + + expect(result).toBe(-1) +}) From f57a9dad89db80826ac125a0f1938851bbee9785 Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Sun, 18 Aug 2019 22:05:19 +0800 Subject: [PATCH 04/11] added explantion and complexity for Find Words That Can Be Formed by Characters. --- .../README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/problems/find-words-that-can-be-formed-by-characters/README.md b/problems/find-words-that-can-be-formed-by-characters/README.md index f4192c1..51f0250 100644 --- a/problems/find-words-that-can-be-formed-by-characters/README.md +++ b/problems/find-words-that-can-be-formed-by-characters/README.md @@ -1,7 +1,23 @@ # Find Words That Can Be Formed by Characters -LeetCode #: 1160 [Link](https://leetcode.com/problems/find-words-that-can-be-formed-by-characters/) +LeetCode #: [1160](https://leetcode.com/problems/find-words-that-can-be-formed-by-characters/) Difficulty: Easy Topics: Array, hash table. + +## Explanation + +This solution makes use of JavaScript [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) objects as hashtable to store the counts of characters. + +## Complexity Analysis + +Assume `m` is the total number of characters in all the word in `words`, and `n` is the total number of characters in `chars`. + +### Time complexity: O(m+n) + +In the worst case, the solution will go through all the `m` and `n` characters once. + +### Space complexity: O(m+n) + +In the worst case, the size of the hash tables would be `m` and `n`. From 7b57cdb06d0220fe77d568105ae2237e0b1dd9f5 Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Sun, 18 Aug 2019 22:20:38 +0800 Subject: [PATCH 05/11] code refactor. --- .../solution.js | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/problems/find-words-that-can-be-formed-by-characters/solution.js b/problems/find-words-that-can-be-formed-by-characters/solution.js index 3718283..2840722 100644 --- a/problems/find-words-that-can-be-formed-by-characters/solution.js +++ b/problems/find-words-that-can-be-formed-by-characters/solution.js @@ -1,3 +1,30 @@ +/** + * Check if the word is within charMap. + * @param {*} word + * @param {*} charMap + */ +const isWordInCharMap = (word, charMap) => { + const wMap = new Map() + const ws = word.split('') + + for (const w of ws) { + if (wMap.has(w)) { + wMap.set(w, wMap.get(w) + 1) + } else { + wMap.set(w, 1) + } + + if ( + (!charMap.get(w)) || + (wMap.get(w) > charMap.get(w)) + ) { + return false + } + } + + return true +} + /** * @param {string[]} words * @param {string} chars @@ -13,33 +40,11 @@ const countCharacters = function (words, chars) { } }) - let length = 0 - - for (const word of words) { - let ok = true - const ws = word.split('') - const wMap = new Map() - - for (const w of ws) { - if (wMap.has(w)) { - wMap.set(w, wMap.get(w) + 1) - } else { - wMap.set(w, 1) - } - - if ( - (!charMap.get(w)) || - (wMap.get(w) > charMap.get(w)) - ) { - ok = false - break - } - } - - if (ok) { - length += word.length - } - } + const length = words.reduce((acc, cur) => { + return isWordInCharMap(cur, charMap) + ? acc + cur.length + : acc + }, 0) return length } From 8858efba4160fcaca28de55bed5029b8ea3311ed Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Sun, 18 Aug 2019 22:49:46 +0800 Subject: [PATCH 06/11] code enhancement: remove map and for loop. --- .../solution.js | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/problems/maximum-level-sum-of-a-binary-tree/solution.js b/problems/maximum-level-sum-of-a-binary-tree/solution.js index 042315c..557be91 100644 --- a/problems/maximum-level-sum-of-a-binary-tree/solution.js +++ b/problems/maximum-level-sum-of-a-binary-tree/solution.js @@ -5,12 +5,14 @@ * this.left = this.right = null; * } */ + /** * @param {TreeNode} root * @return {number} */ const maxLevelSum = function (root) { - const map = {} + let maxSum = Number.MIN_SAFE_INTEGER + let maxSumLevel = 0 const nodeQueue = [root] let currentLevel = 1 @@ -20,22 +22,23 @@ const maxLevelSum = function (root) { while (nodeQueue.length > 0) { const node = nodeQueue.shift() - if (node !== null) { - currentLevelSum += node.val + currentLevelSum += node.val - if (node.left) { - nodeQueue.push(node.left) - } + if (node.left) { + nodeQueue.push(node.left) + } - if (node.right) { - nodeQueue.push(node.right) - } + if (node.right) { + nodeQueue.push(node.right) } currentLevelNodeCount -= 1 if (currentLevelNodeCount === 0) { - map[currentLevel] = currentLevelSum + if (currentLevelSum > maxSum) { + maxSum = currentLevelSum + maxSumLevel = currentLevel + } currentLevel += 1 currentLevelSum = 0 @@ -43,16 +46,7 @@ const maxLevelSum = function (root) { } } - let level = 0 - let maxSum = Number.MIN_SAFE_INTEGER - for (const [key, value] of Object.entries(map)) { - if (value > maxSum) { - maxSum = value - level = parseInt(key) - } - } - - return level + return maxSumLevel } module.exports = maxLevelSum From 418eacd6fde6ea76c210624c128ea4d9b98260dd Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Sun, 18 Aug 2019 23:04:07 +0800 Subject: [PATCH 07/11] added complexity analysis for maximum level sum of a binary tree. --- .../maximum-level-sum-of-a-binary-tree/README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/problems/maximum-level-sum-of-a-binary-tree/README.md b/problems/maximum-level-sum-of-a-binary-tree/README.md index 2b645a4..77ade8a 100644 --- a/problems/maximum-level-sum-of-a-binary-tree/README.md +++ b/problems/maximum-level-sum-of-a-binary-tree/README.md @@ -1,7 +1,19 @@ # Maximum Level Sum of a Binary Tree -LeetCode #: 1161 [Link](https://leetcode.com/problems/maximum-level-sum-of-a-binary-tree/) +LeetCode #: [1161](https://leetcode.com/problems/maximum-level-sum-of-a-binary-tree/) Difficulty: Medium -Topic: Binary Tree +Topic: Binary Tree, Graph. + +## Complexity Analysis + +Assume `n` is the number of nodes in the `root` tree. + +### Time complexity: O(n) + +The solution will go through all the `n` nodes once. + +### Space complexity: O(1) + +The extra space used is always the same regardless of the tree size. From bd114a9cea2b9ca00337a91bcfc0c5d3fd2c017f Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Mon, 19 Aug 2019 00:16:32 +0800 Subject: [PATCH 08/11] clean up code. --- .../as-far-from-land-as-possible/solution.js | 169 ++++++++---------- 1 file changed, 70 insertions(+), 99 deletions(-) diff --git a/problems/as-far-from-land-as-possible/solution.js b/problems/as-far-from-land-as-possible/solution.js index 43aaa76..98268c8 100644 --- a/problems/as-far-from-land-as-possible/solution.js +++ b/problems/as-far-from-land-as-possible/solution.js @@ -1,113 +1,72 @@ -const createDistances = (grid) => { - const distance = Array.from(grid, (rowEl, rowInd) => { - return Array.from(rowEl, (colEl, colInd) => { - return null - }) - }) - - return distance -} - -const getNextSquares = (distanceGrid, newSquare, squares) => { - if ( - distanceGrid[newSquare.row] && - distanceGrid[newSquare.row][newSquare.col] === null - ) { - squares.push(newSquare) - distanceGrid[newSquare.row][newSquare.col] = -1 +/** + * Convert land's adjacent waters into new lands, and return the new lands. This will mutate values in the input array. + * @param {*} input + * @param {*} land + */ +const getAdjacentLands = (input, land) => { + const nextLands = [] + + if (land.row - 1 >= 0) { + if (input[land.row - 1] && input[land.row - 1][land.col] === 0) { + input[land.row - 1][land.col] = 1 + nextLands.push({ row: land.row - 1, col: land.col }) + } } - return squares -} - -const calculateDistanceInfo = (distanceGrid, distanceSquares, distanceSumDiffs) => { - const currentDistance = distanceSquares.length - 1 - const squares = distanceSquares[currentDistance] - - // const hrtimeSquares = process.hrtime() - for (const square of squares) { - distanceGrid[square.row][square.col] = currentDistance - } - // const hrtimeSquaresDiff = process.hrtime(hrtimeSquares) - // console.log('hrtimeSquaresDiff: ', hrtimeSquaresDiff[1] / 1000000) - - // const hrtimeNextSquares = process.hrtime() - let nextSquares = [] - for (const square of squares) { - nextSquares = getNextSquares(distanceGrid, { row: square.row - 1, col: square.col, sum: square.row - 1 + square.col, diff: square.row - 1 - square.col }, nextSquares) - nextSquares = getNextSquares(distanceGrid, { row: square.row, col: square.col - 1, sum: square.row + (square.col - 1), diff: square.row - (square.col - 1) }, nextSquares) - nextSquares = getNextSquares(distanceGrid, { row: square.row, col: square.col + 1, sum: square.row + (square.col + 1), diff: square.row - (square.col + 1) }, nextSquares) - nextSquares = getNextSquares(distanceGrid, { row: square.row + 1, col: square.col, sum: square.row + 1 + square.col, diff: square.row + 1 - square.col }, nextSquares) + if (land.row + 1 < input.length) { + if (input[land.row + 1] && input[land.row + 1][land.col] === 0) { + input[land.row + 1][land.col] = 1 + nextLands.push({ row: land.row + 1, col: land.col }) + } } - // const hrtimeNextSquaresDiff = process.hrtime(hrtimeNextSquares) - // console.log('hrtimeNextSquaresDiff: ', hrtimeNextSquaresDiff[1] / 1000000) - - if (nextSquares.length === 0) { - return { - distanceGrid: distanceGrid, - distanceSquares: distanceSquares, - distanceSumDiffs: distanceSumDiffs + if (land.col - 1 >= 0) { + if (input[land.row][land.col - 1] === 0) { + input[land.row][land.col - 1] = 1 + nextLands.push({ row: land.row, col: land.col - 1 }) } } - distanceSquares.push(nextSquares) - - const sumDiffs = nextSquares.reduce( - (acc, cur) => { - acc.minSum = Math.min(acc.minSum, cur.sum) - acc.maxSum = Math.max(acc.maxSum, cur.sum) - acc.minDiff = Math.min(acc.minDiff, cur.diff) - acc.maxDiff = Math.max(acc.maxDiff, cur.diff) - - return acc - }, - { - minSum: Number.MAX_SAFE_INTEGER, - maxSum: Number.MIN_SAFE_INTEGER, - minDiff: Number.MAX_SAFE_INTEGER, - maxDiff: Number.MIN_SAFE_INTEGER + const maxCol = input[land.row].length + if (land.col + 1 < maxCol) { + if (input[land.row][land.col + 1] === 0) { + input[land.row][land.col + 1] = 1 + nextLands.push({ row: land.row, col: land.col + 1 }) } - ) - - distanceSumDiffs.push(sumDiffs) + } - return calculateDistanceInfo(distanceGrid, distanceSquares, distanceSumDiffs) + return nextLands } -const getDistanceInfo = (grid, offices) => { - const emptyDistanceGrid = createDistances(grid) - - const distanceOffices = [] - distanceOffices.push(offices) - - const distanceSumDiffs = [] - const sumDiffs = distanceOffices[0].reduce( - (acc, cur) => { - acc.minSum = Math.min(acc.minSum, cur.sum) - acc.maxSum = Math.max(acc.maxSum, cur.sum) - acc.minDiff = Math.min(acc.minDiff, cur.diff) - acc.maxDiff = Math.max(acc.maxDiff, cur.diff) - - return acc - }, - { - minSum: Number.MAX_SAFE_INTEGER, - maxSum: Number.MIN_SAFE_INTEGER, - minDiff: Number.MAX_SAFE_INTEGER, - maxDiff: Number.MIN_SAFE_INTEGER - } - ) +/** + * Perform breadth-first search through the input array, converting 0 to 1 while calculating the distance from the original lands. This will mutate values in the input array. + * @param {*} input Array. + * @param {*} lands Current lands. Array of { row, col }. + * @param {Number} distance Current distance of lands. + */ +const getDistance = (input, lands, distance) => { + const nextLands = [] + + for (const land of lands) { + const tempNextLands = getAdjacentLands(input, land) + nextLands.push(...tempNextLands) + } - distanceSumDiffs.push(sumDiffs) + if (nextLands.length === 0) { + return distance + } - return calculateDistanceInfo(emptyDistanceGrid, distanceOffices, distanceSumDiffs) -} + const nextDistance = distance + 1 -/// ///// + return getDistance(input, nextLands, nextDistance) +} -const maxDistance = (input) => { - const offices = [] +/** + * Iterare through all cells in input[row][col] and returns { lands[{row, col}], hasLand, hasWater }. + * @param {*} input + */ +const getInitialInfo = (input) => { + const lands = [] let hasLand = false let hasWater = false @@ -120,7 +79,7 @@ const maxDistance = (input) => { if (elj === 1) { hasLand = true - offices.push({ + lands.push({ row: i, col: j }) @@ -132,13 +91,25 @@ const maxDistance = (input) => { } } - if (!(hasLand && hasWater)) { + return { + lands, + hasLand, + hasWater + } +} + +const maxDistance = (input) => { + const { lands, hasLand, hasWater } = getInitialInfo(input) + + if (!hasWater) { return -1 } - const distanceInfo = getDistanceInfo(input, offices) + if (!hasLand) { + return -1 + } - return distanceInfo.distanceSquares.length - 1 + return getDistance(input, lands, 0) } module.exports = maxDistance From b10dda4e243125032ce30192190f097d8a2c707e Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Mon, 19 Aug 2019 00:16:42 +0800 Subject: [PATCH 09/11] added more test. --- .../as-far-from-land-as-possible/solution.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/problems/as-far-from-land-as-possible/solution.test.js b/problems/as-far-from-land-as-possible/solution.test.js index 050fbe1..158f765 100644 --- a/problems/as-far-from-land-as-possible/solution.test.js +++ b/problems/as-far-from-land-as-possible/solution.test.js @@ -31,3 +31,15 @@ test('All land', () => { expect(result).toBe(-1) }) + +test('One land in the middle', () => { + const input = [ + [0, 0, 0], + [0, 1, 0], + [0, 0, 0] + ] + + const result = maxDistance(input) + + expect(result).toBe(4) +}) From d237a2288e718dd51fed250a1371bf377d48cb47 Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Mon, 19 Aug 2019 00:29:46 +0800 Subject: [PATCH 10/11] edited complexity analysis. --- problems/as-far-from-land-as-possible/README.md | 8 ++++++++ problems/maximum-level-sum-of-a-binary-tree/README.md | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/problems/as-far-from-land-as-possible/README.md b/problems/as-far-from-land-as-possible/README.md index a3b4789..9ed6d41 100644 --- a/problems/as-far-from-land-as-possible/README.md +++ b/problems/as-far-from-land-as-possible/README.md @@ -5,3 +5,11 @@ LeetCode #: [1162](https://leetcode.com/problems/as-far-from-land-as-possible/) Difficulty: Medium Topic: Breadth-First Search, Graph. + +## Complexity Analysis + +Assume `n` is the total number of cells in the input array. + +### Time complexity: O(n) + +The solution will go through all the `n` cells twice. The first time is to get the initial list of lands. The second time is to perform breadth-first search based on the list of lands to get the maximum distance. diff --git a/problems/maximum-level-sum-of-a-binary-tree/README.md b/problems/maximum-level-sum-of-a-binary-tree/README.md index 77ade8a..8aaf32e 100644 --- a/problems/maximum-level-sum-of-a-binary-tree/README.md +++ b/problems/maximum-level-sum-of-a-binary-tree/README.md @@ -13,7 +13,3 @@ Assume `n` is the number of nodes in the `root` tree. ### Time complexity: O(n) The solution will go through all the `n` nodes once. - -### Space complexity: O(1) - -The extra space used is always the same regardless of the tree size. From 5a8a57f0d0fb6f7fd26e6d623ae55abec2b46e38 Mon Sep 17 00:00:00 2001 From: Gan Eng Chin Date: Mon, 19 Aug 2019 00:35:34 +0800 Subject: [PATCH 11/11] updated main readme. --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e2f2802..9ee8b47 100644 --- a/README.md +++ b/README.md @@ -45,12 +45,15 @@ Folder structure in this repository: https://github.com/ecgan/leetc |-----------:|:------|:-----------|:-------| | 1 | [Two Sum](/problems/two-sum) | Easy | Array, hash table | | 136 | [Single Number](/problems/single-number) | Easy | Hash table, bit manipulation | -| 349 | [Intersection of Two Arrays](/problems/intersection-of-two-arrays) | Easy | Hash Table, two pointers, binary search, sort, set | +| 349 | [Intersection of Two Arrays](/problems/intersection-of-two-arrays) | Easy | Hash table, two pointers, binary search, sort, set | | 1144 | [Decrease Elements To Make Array Zigzag](/problems/decrease-elements-to-make-array-zigzag) | Medium | Array | | 1145 | [Binary Tree Coloring Game](/problems/binary-tree-coloring-game/) | Medium | Tree, depth-first search | | 1150 | [Check If a Number Is Majority Element in a Sorted Array](/problems/is-a-a-majority-element) | Easy | Array, binary search | | 1153 | [String Transforms Into Another String](/problems/string-transforms-into-another-string) | Hard | Graph | -| 1154 | [Day of the Year](/problems/ordinal-number-of-date) | Easy | - | +| 1154 | [Day of the Year](/problems/ordinal-number-of-date) | Easy | Math | +| 1160 | [Find Words That Can Be Formed by Characters](/problems/find-words-that-can-be-formed-by-characters) | Easy | Array, hash table | +| 1161 | [Maximum Level Sum of a Binary Tree](/problems/maximum-level-sum-of-a-binary-tree) | Medium | Graph | +| 1162 | [As Far from Land as Possible](/problems/as-far-from-land-as-possible) | Medium | Breadth-first search, graph | ## Questions / Issues