diff --git a/book/D-interview-questions-solutions.asc b/book/D-interview-questions-solutions.asc index d7228268..fb9b27c1 100644 --- a/book/D-interview-questions-solutions.asc +++ b/book/D-interview-questions-solutions.asc @@ -843,6 +843,90 @@ This algorithm only works with DFS. // +:leveloffset: +1 + +=== Solutions for Sorting Questions +(((Interview Questions Solutions, sorting))) + +:leveloffset: -1 + + +[#sorting-q-merge-intervals] +include::content/part03/sorting-algorithms.asc[tag=sorting-q-merge-intervals] + +The first thing we need to understand is all the different possibilities for overlaps: + +image::merge-intervals-cases.png[merge intervals cases] + +One way to solve this problem, is sorting by start time. That will eliminate half of the cases! + +Since A will always start before B, only 3 cases apply: +- No overlap: `[[1, 3], [4, 6]]`. +- Overlap at the end: `[[1, 3], [2, 4]]`. +- Eclipse: `[[1, 9], [3, 7]]`. + +*Algorithm*: + +* Sort intervals by start time +* If the `curr`ent interval's start time is _equal_ or less than the `last` interval's end time, then we have an overlap. +** Overlaps has two cases: 1) `curr`'s end is larger 2) `last`'s end is larger. For both cases `Math.max` works. +* If there's no overlap, we add the interval to the solution. + +*Implementation*: + +[source, javascript] +---- +include::interview-questions/merge-intervals.js[tags=description;solution] +---- + +For the first interval, it will be added straight to the solution array. For all others, we will do the comparison. + +*Complexity Analysis*: + +- Time: `O(n log n)`. Standard libraries has a sorting time of `O(n log n)`, then we visit each interval in `O(n)`. +- Space: `O(n)`. In the worst-case is when there's no overlapping intervals. The size of the solution array would be `n`. + + + + + + + +// + +[#sorting-q-FILENAME] +include::content/part03/sorting-algorithms.asc[tag=sorting-q-FILENAME] + +RESTATE REQUIREMENTS AND DESCRIPTIONS + +*Algorithm*: + +* STEP 1 +* STEP 2 +** STEP 2.1 +** STEP 2.2 + +*Implementation*: + +[source, javascript] +---- +include::interview-questions/FILENAME.js[tags=description;solution] +---- + +IMPLEMENTATION NOTES + +*Complexity Analysis*: + +- Time: `O(?)`. WHY? +- Space: `O(?)`. WHY? + + + + + + + +// diff --git a/book/content/part04/sorting-algorithms.asc b/book/content/part04/sorting-algorithms.asc index 67ea34a4..5a8f21a4 100644 --- a/book/content/part04/sorting-algorithms.asc +++ b/book/content/part04/sorting-algorithms.asc @@ -139,3 +139,77 @@ We explored many algorithms some of them simple and other more performant. Also, // | Tim sort | O(n log n) | O(log n) | Yes | No | No | Yes |=== // end::table[] + + + + + + + + + +==== Practice Questions +(((Interview Questions, sorting))) + + + + + +// tag::sorting-q-merge-intervals[] +===== TITLE + +*so-1*) _Given an array of intervals `[start, end]`, merge all overlapping intervals._ + +// end::sorting-q-merge-intervals[] + +// _Seen in interviews at: X._ + +*Starter code*: + +[source, javascript] +---- +include::../../interview-questions/merge-intervals.js[tags=description;placeholder] +---- + +*Examples*: + +[source, javascript] +---- +merge([[0, 2], [2, 4]]); // [[0, 4]] (0-2 overlaps with 2-4) +merge([[2, 2], [3, 4]]); // [[2, 2], [3, 4]] (no overlap) +merge([[1, 10], [3, 4]]); // [[1, 10]] (1-10 covers the other) +---- + + +_Solution: <>_ + + + + + + +// tag::sorting-q-FILENAME[] +===== TITLE + +*sorting_INITIALS-NUMBER*) _._ + +// end::sorting-q-FILENAME[] + +// _Seen in interviews at: X._ + +*Starter code*: + +[source, javascript] +---- +include::../../interview-questions/FILENAME.js[tags=description;placeholder] +---- + +*Examples*: + +[source, javascript] +---- +FN([]); // 3 (EXPLANATION) +---- + + +_Solution: <>_ diff --git a/book/images/merge-intervals-cases.png b/book/images/merge-intervals-cases.png new file mode 100644 index 00000000..574438a9 Binary files /dev/null and b/book/images/merge-intervals-cases.png differ diff --git a/book/images/merge-intervals-cases.png:Zone.Identifier b/book/images/merge-intervals-cases.png:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/book/interview-questions/merge-intervals.js b/book/interview-questions/merge-intervals.js new file mode 100644 index 00000000..3c62d5cc --- /dev/null +++ b/book/interview-questions/merge-intervals.js @@ -0,0 +1,27 @@ +// const { } = require('../../src/index'); + +// tag::description[] +function merge(intervals) { + // end::description[] + // tag::placeholder[] + // write your code here... + // end::placeholder[] + // tag::solution[] + const ans = []; + + intervals.sort((a, b) => a[0] - b[0]); // sort by start time + + for (let i = 0; i < intervals.length; i++) { + const last = ans[ans.length - 1]; + const curr = intervals[i]; + if (last && last[1] >= curr[0]) { // check for overlaps + last[1] = Math.max(last[1], curr[1]); + } else ans.push(curr); + } + return ans; + // end::solution[] + // tag::description[] +} +// end::description[] + +module.exports = { merge }; diff --git a/book/interview-questions/merge-intervals.spec.js b/book/interview-questions/merge-intervals.spec.js new file mode 100644 index 00000000..da875e4d --- /dev/null +++ b/book/interview-questions/merge-intervals.spec.js @@ -0,0 +1,30 @@ +const { merge } = require('./merge-intervals'); +// const { } = require('../../src/index'); + +[merge].forEach((fn) => { + describe(`TOPIC: ${fn.name}`, () => { + it('should work with null/empty', () => { + const actual = fn([]); + const expected = []; + expect(actual).toEqual(expected); + }); + + it('should work with small case', () => { + const actual = fn([[1, 3]]); + const expected = [[1, 3]]; + expect(actual).toEqual(expected); + }); + + it('should work with other case', () => { + const actual = fn([[0, 1], [1, 3], [3, 5], [6, 6]]); + const expected = [[0, 5], [6, 6]]; + expect(actual).toEqual(expected); + }); + + it('should work with other case', () => { + const actual = fn([[10, 99], [20, 50], [9, 11], [98, 100]]); + const expected = [[9, 100]]; + expect(actual).toEqual(expected); + }); + }); +});