diff --git a/problems/possible-bipartition/README.md b/problems/possible-bipartition/README.md new file mode 100644 index 0000000..ff66a07 --- /dev/null +++ b/problems/possible-bipartition/README.md @@ -0,0 +1,55 @@ +# Possible Bipartition + +LeetCode #: [886](https://leetcode.com/problems/possible-bipartition/) + +Difficulty: Medium + +Topics: Depth-first Search. + +## Problem + +Given a set of `N` people (numbered `1, 2, ..., N`), we would like to split everyone into two groups of any size. + +Each person may dislike some other people, and they should not go into the same group. + +Formally, if `dislikes[i] = [a, b]`, it means it is not allowed to put the people numbered `a` and `b` into the same group. + +Return `true` if and only if it is possible to split everyone into two groups in this way. + +Example 1: + +```text +Input: N = 4, dislikes = [[1,2],[1,3],[2,4]] +Output: true +Explanation: group1 [1,4], group2 [2,3] +``` + +Example 2: + +```text +Input: N = 3, dislikes = [[1,2],[1,3],[2,3]] +Output: false +``` + +Example 3: + +```text +Input: N = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]] +Output: false +``` + +Note: + +- `1 <= N <= 2000` +- `0 <= dislikes.length <= 10000` +- `1 <= dislikes[i][j] <= N` +- `dislikes[i][0] < dislikes[i][1]` +- There does not exist `i != j` for which `dislikes[i] == dislikes[j]`. + +## Complexity Analysis + +Assume E is the length of `dislikes` array. + +Time complexity: O(N+E). + +Space complexity: O(N+E). diff --git a/problems/possible-bipartition/possibleBipartition.js b/problems/possible-bipartition/possibleBipartition.js new file mode 100644 index 0000000..37acd84 --- /dev/null +++ b/problems/possible-bipartition/possibleBipartition.js @@ -0,0 +1,57 @@ +const getDfsFn = (lists, numGroupMap) => { + const dfs = (num, group) => { + if (numGroupMap.has(num)) { + return numGroupMap.get(num) === group + } + + numGroupMap.set(num, group) + + const dislikes = lists[num] || [] + for (let i = 0; i < dislikes.length; i++) { + if (!dfs(dislikes[i], group ^ 1)) { + return false + } + } + + return true + } + + return dfs +} + +const getDislikesLists = (dislikes) => { + const lists = [] + + for (let i = 0; i < dislikes.length; i++) { + const [a, b] = dislikes[i] + + lists[a] = lists[a] || [] + lists[a].push(b) + + lists[b] = lists[b] || [] + lists[b].push(a) + } + + return lists +} + +/** + * @param {number} N + * @param {number[][]} dislikes + * @return {boolean} + */ +const possibleBipartition = function (N, dislikes) { + const lists = getDislikesLists(dislikes) + const numGroupMap = new Map() + const dfs = getDfsFn(lists, numGroupMap) + + for (let i = 1; i <= N; i++) { + if (!numGroupMap.has(i) && !dfs(i, 0)) { + return false + } + } + + return true +} + +module.exports = possibleBipartition diff --git a/problems/possible-bipartition/possibleBipartition.test.js b/problems/possible-bipartition/possibleBipartition.test.js new file mode 100644 index 0000000..70f11c0 --- /dev/null +++ b/problems/possible-bipartition/possibleBipartition.test.js @@ -0,0 +1,37 @@ +const possibleBipartition = require('./possibleBipartition') + +test('Example 1', () => { + const N = 4 + const dislikes = [[1, 2], [1, 3], [2, 4]] + + const result = possibleBipartition(N, dislikes) + + expect(result).toBe(true) +}) + +test('Example 2', () => { + const N = 3 + const dislikes = [[1, 2], [1, 3], [2, 3]] + + const result = possibleBipartition(N, dislikes) + + expect(result).toBe(false) +}) + +test('Example 3', () => { + const N = 5 + const dislikes = [[1, 2], [2, 3], [3, 4], [4, 5], [1, 5]] + + const result = possibleBipartition(N, dislikes) + + expect(result).toBe(false) +}) + +test('N=1, no dislikes', () => { + const N = 1 + const dislikes = [] + + const result = possibleBipartition(N, dislikes) + + expect(result).toBe(true) +})