From d7a18f73a301f7427a16c0794c6a07d4b0883847 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 22 Dec 2023 15:26:15 +0800 Subject: [PATCH 1/2] feat: add solutions to lc problems: No.303~305 --- .../README.md | 90 ++--- .../README_EN.md | 92 ++--- .../Solution.c | 61 +-- .../Solution.cpp | 41 +- .../Solution.js | 2 +- .../Solution.php | 17 +- .../Solution.rs | 10 +- .../Solution.ts | 2 +- .../README.md | 3 +- .../README_EN.md | 11 +- .../0305.Number of Islands II/README.md | 355 +++++++++++------- .../0305.Number of Islands II/README_EN.md | 296 +++++++++++---- .../0305.Number of Islands II/Solution.cpp | 96 +++-- .../0305.Number of Islands II/Solution.go | 60 ++- .../0305.Number of Islands II/Solution.java | 103 +++-- .../0305.Number of Islands II/Solution.py | 74 ++-- .../0305.Number of Islands II/Solution.ts | 59 +++ 17 files changed, 876 insertions(+), 496 deletions(-) create mode 100644 solution/0300-0399/0305.Number of Islands II/Solution.ts diff --git a/solution/0300-0399/0303.Range Sum Query - Immutable/README.md b/solution/0300-0399/0303.Range Sum Query - Immutable/README.md index f7e1b3fe77262..68f3da4569c3a 100644 --- a/solution/0300-0399/0303.Range Sum Query - Immutable/README.md +++ b/solution/0300-0399/0303.Range Sum Query - Immutable/README.md @@ -54,9 +54,9 @@ numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1)) **方法一:前缀和** -前缀和计算公式:`s[i + 1] = s[i] + nums[i]`。 +我们创建一个长度为 $n + 1$ 的前缀和数组 $s$,其中 $s[i]$ 表示前 $i$ 个元素的前缀和,即 $s[i] = \sum_{j=0}^{i-1} nums[j]$,那么索引 $[left, right]$ 之间的元素的和就可以表示为 $s[right + 1] - s[left]$。 -初始化的时间复杂度是 $O(n)$,每次查询的时间复杂度是 $O(1)$。其中 $n$ 是数组的长度。 +初始化前缀和数组 $s$ 的时间复杂度为 $O(n)$,查询的时间复杂度为 $O(1)$。空间复杂度 $O(n)$。 @@ -111,17 +111,20 @@ class NumArray { ```cpp class NumArray { public: - vector s; - NumArray(vector& nums) { int n = nums.size(); s.resize(n + 1); - for (int i = 0; i < n; ++i) s[i + 1] = s[i] + nums[i]; + for (int i = 0; i < n; ++i) { + s[i + 1] = s[i] + nums[i]; + } } int sumRange(int left, int right) { return s[right + 1] - s[left]; } + +private: + vector s; }; /** @@ -166,7 +169,7 @@ func (this *NumArray) SumRange(left int, right int) int { */ var NumArray = function (nums) { const n = nums.length; - this.s = new Array(n + 1).fill(0); + this.s = Array(n + 1).fill(0); for (let i = 0; i < n; ++i) { this.s[i + 1] = this.s[i] + nums[i]; } @@ -196,7 +199,7 @@ class NumArray { constructor(nums: number[]) { const n = nums.length; - this.s = new Array(n + 1).fill(0); + this.s = Array(n + 1).fill(0); for (let i = 0; i < n; ++i) { this.s[i + 1] = this.s[i] + nums[i]; } @@ -218,34 +221,7 @@ class NumArray { ```rust struct NumArray { - nums: Vec, -} - -/** - * `&self` means the method takes an immutable reference. - * If you need a mutable reference, change it to `&mut self` instead. - */ -impl NumArray { - fn new(nums: Vec) -> Self { - Self { - nums, - } - } - - fn sum_range(&self, left: i32, right: i32) -> i32 { - let (left, right) = (left as usize, right as usize); - self.nums[left..=right].iter().sum::() - } -}/** - * Your NumArray object will be instantiated and called as such: - * let obj = NumArray::new(nums); - * let ret_1: i32 = obj.sum_range(left, right); - */ -``` - -```rust -struct NumArray { - sums: Vec, + s: Vec, } /** @@ -255,15 +231,15 @@ struct NumArray { impl NumArray { fn new(mut nums: Vec) -> Self { let n = nums.len(); - let mut sums = vec![0; n + 1]; + let mut s = vec![0; n + 1]; for i in 0..n { - sums[i + 1] = sums[i] + nums[i]; + s[i + 1] = s[i] + nums[i]; } - Self { sums } + Self { s } } fn sum_range(&self, left: i32, right: i32) -> i32 { - self.sums[(right + 1) as usize] - self.sums[left as usize] + self.s[(right + 1) as usize] - self.s[left as usize] } }/** * Your NumArray object will be instantiated and called as such: @@ -276,25 +252,26 @@ impl NumArray { ```c typedef struct { - int* sums; + int* s; } NumArray; -NumArray* numArrayCreate(int* nums, int numsSize) { - int* sums = malloc(sizeof(int) * (numsSize + 1)); - memset(sums, 0, numsSize + 1); - for (int i = 0; i < numsSize; i++) { - sums[i + 1] = sums[i] + nums[i]; +NumArray* numArrayCreate(int* nums, int n) { + int* s = malloc(sizeof(int) * (n + 1)); + s[0] = 0; + for (int i = 0; i < n; i++) { + s[i + 1] = s[i] + nums[i]; } - NumArray* res = malloc(sizeof(NumArray)); - res->sums = sums; - return res; + NumArray* obj = malloc(sizeof(NumArray)); + obj->s = s; + return obj; } int numArraySumRange(NumArray* obj, int left, int right) { - return obj->sums[right + 1] - obj->sums[left]; + return obj->s[right + 1] - obj->s[left]; } void numArrayFree(NumArray* obj) { + free(obj->s); free(obj); } @@ -315,20 +292,27 @@ class NumArray { * @param Integer[] $nums */ function __construct($nums) { - $this->sum = [0]; - for ($i = 0; $i < count($nums); $i++) { - array_push($this->sum, $this->sum[$i] + $nums[$i]); + $this->s = [0]; + foreach ($nums as $x) { + $this->s[] = $this->s[count($this->s) - 1] + $x; } } + /** * @param Integer $left * @param Integer $right * @return Integer */ function sumRange($left, $right) { - return $this->sum[$right + 1] - $this->sum[$left]; + return $this->s[$right + 1] - $this->s[$left]; } } + +/** + * Your NumArray object will be instantiated and called as such: + * $obj = NumArray($nums); + * $ret_1 = $obj->sumRange($left, $right); + */ ``` ### **...** diff --git a/solution/0300-0399/0303.Range Sum Query - Immutable/README_EN.md b/solution/0300-0399/0303.Range Sum Query - Immutable/README_EN.md index 3ae04765ad644..8f772fa24ec29 100644 --- a/solution/0300-0399/0303.Range Sum Query - Immutable/README_EN.md +++ b/solution/0300-0399/0303.Range Sum Query - Immutable/README_EN.md @@ -46,6 +46,12 @@ numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3 ## Solutions +**Solution 1: Prefix Sum** + +We create a prefix sum array $s$ of length $n + 1$, where $s[i]$ represents the prefix sum of the first $i$ elements, that is, $s[i] = \sum_{j=0}^{i-1} nums[j]$. Therefore, the sum of the elements between the indices $[left, right]$ can be expressed as $s[right + 1] - s[left]$. + +The time complexity for initializing the prefix sum array $s$ is $O(n)$, and the time complexity for querying is $O(1)$. The space complexity is $O(n)$. + ### **Python3** @@ -95,17 +101,20 @@ class NumArray { ```cpp class NumArray { public: - vector s; - NumArray(vector& nums) { int n = nums.size(); s.resize(n + 1); - for (int i = 0; i < n; ++i) s[i + 1] = s[i] + nums[i]; + for (int i = 0; i < n; ++i) { + s[i + 1] = s[i] + nums[i]; + } } int sumRange(int left, int right) { return s[right + 1] - s[left]; } + +private: + vector s; }; /** @@ -150,7 +159,7 @@ func (this *NumArray) SumRange(left int, right int) int { */ var NumArray = function (nums) { const n = nums.length; - this.s = new Array(n + 1).fill(0); + this.s = Array(n + 1).fill(0); for (let i = 0; i < n; ++i) { this.s[i + 1] = this.s[i] + nums[i]; } @@ -180,7 +189,7 @@ class NumArray { constructor(nums: number[]) { const n = nums.length; - this.s = new Array(n + 1).fill(0); + this.s = Array(n + 1).fill(0); for (let i = 0; i < n; ++i) { this.s[i + 1] = this.s[i] + nums[i]; } @@ -202,34 +211,7 @@ class NumArray { ```rust struct NumArray { - nums: Vec, -} - -/** - * `&self` means the method takes an immutable reference. - * If you need a mutable reference, change it to `&mut self` instead. - */ -impl NumArray { - fn new(nums: Vec) -> Self { - Self { - nums, - } - } - - fn sum_range(&self, left: i32, right: i32) -> i32 { - let (left, right) = (left as usize, right as usize); - self.nums[left..=right].iter().sum::() - } -}/** - * Your NumArray object will be instantiated and called as such: - * let obj = NumArray::new(nums); - * let ret_1: i32 = obj.sum_range(left, right); - */ -``` - -```rust -struct NumArray { - sums: Vec, + s: Vec, } /** @@ -239,15 +221,15 @@ struct NumArray { impl NumArray { fn new(mut nums: Vec) -> Self { let n = nums.len(); - let mut sums = vec![0; n + 1]; + let mut s = vec![0; n + 1]; for i in 0..n { - sums[i + 1] = sums[i] + nums[i]; + s[i + 1] = s[i] + nums[i]; } - Self { sums } + Self { s } } fn sum_range(&self, left: i32, right: i32) -> i32 { - self.sums[(right + 1) as usize] - self.sums[left as usize] + self.s[(right + 1) as usize] - self.s[left as usize] } }/** * Your NumArray object will be instantiated and called as such: @@ -260,25 +242,26 @@ impl NumArray { ```c typedef struct { - int* sums; + int* s; } NumArray; -NumArray* numArrayCreate(int* nums, int numsSize) { - int* sums = malloc(sizeof(int) * (numsSize + 1)); - memset(sums, 0, numsSize + 1); - for (int i = 0; i < numsSize; i++) { - sums[i + 1] = sums[i] + nums[i]; +NumArray* numArrayCreate(int* nums, int n) { + int* s = malloc(sizeof(int) * (n + 1)); + s[0] = 0; + for (int i = 0; i < n; i++) { + s[i + 1] = s[i] + nums[i]; } - NumArray* res = malloc(sizeof(NumArray)); - res->sums = sums; - return res; + NumArray* obj = malloc(sizeof(NumArray)); + obj->s = s; + return obj; } int numArraySumRange(NumArray* obj, int left, int right) { - return obj->sums[right + 1] - obj->sums[left]; + return obj->s[right + 1] - obj->s[left]; } void numArrayFree(NumArray* obj) { + free(obj->s); free(obj); } @@ -299,20 +282,27 @@ class NumArray { * @param Integer[] $nums */ function __construct($nums) { - $this->sum = [0]; - for ($i = 0; $i < count($nums); $i++) { - array_push($this->sum, $this->sum[$i] + $nums[$i]); + $this->s = [0]; + foreach ($nums as $x) { + $this->s[] = $this->s[count($this->s) - 1] + $x; } } + /** * @param Integer $left * @param Integer $right * @return Integer */ function sumRange($left, $right) { - return $this->sum[$right + 1] - $this->sum[$left]; + return $this->s[$right + 1] - $this->s[$left]; } } + +/** + * Your NumArray object will be instantiated and called as such: + * $obj = NumArray($nums); + * $ret_1 = $obj->sumRange($left, $right); + */ ``` ### **...** diff --git a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.c b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.c index 56223f93d7b5c..885e2f173cd07 100644 --- a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.c +++ b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.c @@ -1,30 +1,31 @@ -typedef struct { - int* sums; -} NumArray; - -NumArray* numArrayCreate(int* nums, int numsSize) { - int* sums = malloc(sizeof(int) * (numsSize + 1)); - memset(sums, 0, numsSize + 1); - for (int i = 0; i < numsSize; i++) { - sums[i + 1] = sums[i] + nums[i]; - } - NumArray* res = malloc(sizeof(NumArray)); - res->sums = sums; - return res; -} - -int numArraySumRange(NumArray* obj, int left, int right) { - return obj->sums[right + 1] - obj->sums[left]; -} - -void numArrayFree(NumArray* obj) { - free(obj); -} - -/** - * Your NumArray struct will be instantiated and called as such: - * NumArray* obj = numArrayCreate(nums, numsSize); - * int param_1 = numArraySumRange(obj, left, right); - - * numArrayFree(obj); -*/ +typedef struct { + int* s; +} NumArray; + +NumArray* numArrayCreate(int* nums, int n) { + int* s = malloc(sizeof(int) * (n + 1)); + s[0] = 0; + for (int i = 0; i < n; i++) { + s[i + 1] = s[i] + nums[i]; + } + NumArray* obj = malloc(sizeof(NumArray)); + obj->s = s; + return obj; +} + +int numArraySumRange(NumArray* obj, int left, int right) { + return obj->s[right + 1] - obj->s[left]; +} + +void numArrayFree(NumArray* obj) { + free(obj->s); + free(obj); +} + +/** + * Your NumArray struct will be instantiated and called as such: + * NumArray* obj = numArrayCreate(nums, numsSize); + * int param_1 = numArraySumRange(obj, left, right); + + * numArrayFree(obj); +*/ \ No newline at end of file diff --git a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.cpp b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.cpp index 3c8e4ec54a3cb..6d43748b70011 100644 --- a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.cpp +++ b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.cpp @@ -1,20 +1,23 @@ -class NumArray { -public: - vector s; - - NumArray(vector& nums) { - int n = nums.size(); - s.resize(n + 1); - for (int i = 0; i < n; ++i) s[i + 1] = s[i] + nums[i]; - } - - int sumRange(int left, int right) { - return s[right + 1] - s[left]; - } -}; - -/** - * Your NumArray object will be instantiated and called as such: - * NumArray* obj = new NumArray(nums); - * int param_1 = obj->sumRange(left,right); +class NumArray { +public: + NumArray(vector& nums) { + int n = nums.size(); + s.resize(n + 1); + for (int i = 0; i < n; ++i) { + s[i + 1] = s[i] + nums[i]; + } + } + + int sumRange(int left, int right) { + return s[right + 1] - s[left]; + } + +private: + vector s; +}; + +/** + * Your NumArray object will be instantiated and called as such: + * NumArray* obj = new NumArray(nums); + * int param_1 = obj->sumRange(left,right); */ \ No newline at end of file diff --git a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.js b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.js index ec3c3e932309a..e9b4734f5a6b8 100644 --- a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.js +++ b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.js @@ -3,7 +3,7 @@ */ var NumArray = function (nums) { const n = nums.length; - this.s = new Array(n + 1).fill(0); + this.s = Array(n + 1).fill(0); for (let i = 0; i < n; ++i) { this.s[i + 1] = this.s[i] + nums[i]; } diff --git a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.php b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.php index 742640f6db636..ca25c0e8f5028 100644 --- a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.php +++ b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.php @@ -3,17 +3,24 @@ class NumArray { * @param Integer[] $nums */ function __construct($nums) { - $this->sum = [0]; - for ($i = 0; $i < count($nums); $i++) { - array_push($this->sum, $this->sum[$i] + $nums[$i]); + $this->s = [0]; + foreach ($nums as $x) { + $this->s[] = $this->s[count($this->s) - 1] + $x; } } + /** * @param Integer $left * @param Integer $right * @return Integer */ function sumRange($left, $right) { - return $this->sum[$right + 1] - $this->sum[$left]; + return $this->s[$right + 1] - $this->s[$left]; } -} \ No newline at end of file +} + +/** + * Your NumArray object will be instantiated and called as such: + * $obj = NumArray($nums); + * $ret_1 = $obj->sumRange($left, $right); + */ \ No newline at end of file diff --git a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.rs b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.rs index 5d2a6cccb368e..aedebce9f9640 100644 --- a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.rs +++ b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.rs @@ -1,5 +1,5 @@ struct NumArray { - sums: Vec, + s: Vec, } /** @@ -9,15 +9,15 @@ struct NumArray { impl NumArray { fn new(mut nums: Vec) -> Self { let n = nums.len(); - let mut sums = vec![0; n + 1]; + let mut s = vec![0; n + 1]; for i in 0..n { - sums[i + 1] = sums[i] + nums[i]; + s[i + 1] = s[i] + nums[i]; } - Self { sums } + Self { s } } fn sum_range(&self, left: i32, right: i32) -> i32 { - self.sums[(right + 1) as usize] - self.sums[left as usize] + self.s[(right + 1) as usize] - self.s[left as usize] } }/** * Your NumArray object will be instantiated and called as such: diff --git a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.ts b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.ts index 9ac24a436ee48..2de8967656444 100644 --- a/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.ts +++ b/solution/0300-0399/0303.Range Sum Query - Immutable/Solution.ts @@ -3,7 +3,7 @@ class NumArray { constructor(nums: number[]) { const n = nums.length; - this.s = new Array(n + 1).fill(0); + this.s = Array(n + 1).fill(0); for (let i = 0; i < n; ++i) { this.s[i + 1] = this.s[i] + nums[i]; } diff --git a/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md b/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md index c140bb0b88dfa..d6b8ea17e8dc7 100644 --- a/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md +++ b/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md @@ -73,7 +73,7 @@ $$ 我们在初始化方法中预处理出前缀和数组 $s$,在查询方法中直接返回上述公式的结果即可。 -初始化的时间复杂度为 $O(m\times n)$,查询的时间复杂度为 $O(1)$。 +初始化的时间复杂度为 $O(m \times n)$,查询的时间复杂度为 $O(1)$。空间复杂度为 $O(m \times n)$。 @@ -168,6 +168,7 @@ public: ### **Rust** ```rust + /** * Your NumMatrix object will be instantiated and called as such: * let obj = NumMatrix::new(matrix); diff --git a/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README_EN.md b/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README_EN.md index bef073a8ed9ef..e02447a18ab1b 100644 --- a/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README_EN.md +++ b/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README_EN.md @@ -52,23 +52,23 @@ numMatrix.sumRegion(1, 2, 2, 4); // return 12 (i.e sum of the blue rectangle) ## Solutions -We use $s[i + 1][j + 1]$ to represent the sum of all elements in the upper-left part up to the $i$-th row and $j$-th column, where the indices $i$ and $j$ both start from $0$. +**Solution 1: Two-dimensional Prefix Sum** -We can derive the following prefix sum formula: +We use $s[i + 1][j + 1]$ to represent the sum of all elements in the upper left part of the $i$th row and $j$th column, where indices $i$ and $j$ both start from $0$. We can get the following prefix sum formula: $$ s[i + 1][j + 1] = s[i + 1][j] + s[i][j + 1] - s[i][j] + nums[i][j] $$ -The sum of the elements in the rectangle with $(x_1, y_1)$ and $(x_2, y_2)$ as its upper-left and bottom-right corners respectively, is: +Then, the sum of the elements of the rectangle with $(x_1, y_1)$ and $(x_2, y_2)$ as the upper left corner and lower right corner respectively is: $$ s[x_2 + 1][y_2 + 1] - s[x_2 + 1][y_1] - s[x_1][y_2 + 1] + s[x_1][y_1] $$ -We preprocess the prefix sum array $s$ in the initialization method, and directly return the result of the above formula in the query method. +In the initialization method, we preprocess the prefix sum array $s$, and in the query method, we directly return the result of the above formula. -The time complexity for initialization is $O(m \times n)$, and the time complexity for query is $O(1)$. +The time complexity for initializing is $O(m \times n)$, and the time complexity for querying is $O(1)$. The space complexity is $O(m \times n)$. @@ -159,6 +159,7 @@ public: ### **Rust** ```rust + /** * Your NumMatrix object will be instantiated and called as such: * let obj = NumMatrix::new(matrix); diff --git a/solution/0300-0399/0305.Number of Islands II/README.md b/solution/0300-0399/0305.Number of Islands II/README.md index c6f60607951f5..eed6773192a6c 100644 --- a/solution/0300-0399/0305.Number of Islands II/README.md +++ b/solution/0300-0399/0305.Number of Islands II/README.md @@ -55,72 +55,13 @@ -并查集。 +**方法一:并查集** -并查集模板: +我们用一个二维数组 $grid$ 来表示一个地图,其中 $0$ 和 $1$ 分别表示水和陆地。初始时 $grid$ 中的所有单元格都是水单元格(即所有单元格都是 $0$),用一个变量 $cnt$ 来记录岛屿的数量。而岛屿之间的连通关系可以用一个并查集 $uf$ 来维护。 -模板 1——朴素并查集: +接下来,我们遍历数组 $positions$ 中的每个位置 $(i, j)$,如果 $grid[i][j]$ 为 $1$,说明该位置已经是陆地,我们直接将 $cnt$ 添加到答案中;否则,我们将 $grid[i][j]$ 的值改为 $1$,并且将 $cnt$ 的值增加 $1$。然后,我们遍历该位置的上下左右四个方向,如果某个方向的位置为 $1$,并且该位置与 $(i, j)$ 不属于同一个连通分量,那么我们就将该位置与 $(i, j)$ 进行合并,同时将 $cnt$ 的值减少 $1$。遍历完该位置的上下左右四个方向之后,我们将 $cnt$ 添加到答案中。 -```python -# 初始化,p存储每个点的父节点 -p = list(range(n)) - - -# 返回x的祖宗节点 -def find(x): - if p[x] != x: - # 路径压缩 - p[x] = find(p[x]) - return p[x] - - -# 合并a和b所在的两个集合 -p[find(a)] = find(b) -``` - -模板 2——维护 size 的并查集: - -```python -# 初始化,p存储每个点的父节点,size只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量 -p = list(range(n)) -size = [1] * n - - -# 返回x的祖宗节点 -def find(x): - if p[x] != x: - # 路径压缩 - p[x] = find(p[x]) - return p[x] - - -# 合并a和b所在的两个集合 -if find(a) != find(b): - size[find(b)] += size[find(a)] - p[find(a)] = find(b) -``` - -模板 3——维护到祖宗节点距离的并查集: - -```python -# 初始化,p存储每个点的父节点,d[x]存储x到p[x]的距离 -p = list(range(n)) -d = [0] * n - - -# 返回x的祖宗节点 -def find(x): - if p[x] != x: - t = find(p[x]) - d[x] += d[p[x]] - p[x] = t - return p[x] - - -# 合并a和b所在的两个集合 -p[find(a)] = find(b) -d[find(a)] = distance -``` +时间复杂度 $O(k \times \alpha(m \times n))$ 或 $O(k \times \log(m \times n))$,其中 $k$ 是 $positions$ 的长度,而 $\alpha$ 是阿克曼函数的反函数,本题中 $\alpha(m \times n)$ 可以认为是一个很小的常数。 @@ -129,32 +70,45 @@ d[find(a)] = distance ```python +class UnionFind: + def __init__(self, n: int): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x: int): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a: int, b: int) -> bool: + pa, pb = self.find(a - 1), self.find(b - 1) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + class Solution: def numIslands2(self, m: int, n: int, positions: List[List[int]]) -> List[int]: - def find(x): - if p[x] != x: - p[x] = find(p[x]) - return p[x] - + uf = UnionFind(m * n) grid = [[0] * n for _ in range(m)] - cnt = 0 - p = list(range(m * n)) ans = [] + dirs = (-1, 0, 1, 0, -1) + cnt = 0 for i, j in positions: - if grid[i][j] == 1: + if grid[i][j]: ans.append(cnt) continue grid[i][j] = 1 cnt += 1 - for a, b in [[0, -1], [0, 1], [1, 0], [-1, 0]]: + for a, b in pairwise(dirs): x, y = i + a, j + b - if ( - 0 <= x < m - and 0 <= y < n - and grid[x][y] == 1 - and find(i * n + j) != find(x * n + y) - ): - p[find(i * n + j)] = find(x * n + y) + if 0 <= x < m and 0 <= y < n and grid[x][y] and uf.union(i * n + j, x * n + y): cnt -= 1 ans.append(cnt) return ans @@ -165,21 +119,51 @@ class Solution: ```java -class Solution { - private int[] p; - - public List numIslands2(int m, int n, int[][] positions) { - p = new int[m * n]; - for (int i = 0; i < p.length; ++i) { +class UnionFind { + private final int[] p; + private final int[] size; + + public UnionFind(int n) { + p = new int[n]; + size = new int[n]; + for (int i = 0; i < n; ++i) { p[i] = i; + size[i] = 1; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; } + return true; + } +} + +class Solution { + public List numIslands2(int m, int n, int[][] positions) { int[][] grid = new int[m][n]; + UnionFind uf = new UnionFind(m * n); + int[] dirs = {-1, 0, 1, 0, -1}; int cnt = 0; List ans = new ArrayList<>(); - int[] dirs = {-1, 0, 1, 0, -1}; - for (int[] pos : positions) { - int i = pos[0]; - int j = pos[1]; + for (var p : positions) { + int i = p[0], j = p[1]; if (grid[i][j] == 1) { ans.add(cnt); continue; @@ -187,11 +171,9 @@ class Solution { grid[i][j] = 1; ++cnt; for (int k = 0; k < 4; ++k) { - int x = i + dirs[k]; - int y = j + dirs[k + 1]; + int x = i + dirs[k], y = j + dirs[k + 1]; if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 - && find(x * n + y) != find(i * n + j)) { - p[find(x * n + y)] = find(i * n + j); + && uf.union(i * n + j, x * n + y)) { --cnt; } } @@ -199,33 +181,58 @@ class Solution { } return ans; } +} +``` + +### **C++** + +```cpp +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } - private int find(int x) { + int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } -} -``` -### **C++** +private: + vector p, size; +}; -```cpp class Solution { public: - vector p; - vector numIslands2(int m, int n, vector>& positions) { - p.resize(m * n); - for (int i = 0; i < p.size(); ++i) p[i] = i; - vector> grid(m, vector(n)); - vector ans; + int grid[m][n]; + memset(grid, 0, sizeof(grid)); + UnionFind uf(m * n); + int dirs[5] = {-1, 0, 1, 0, -1}; int cnt = 0; - vector dirs = {-1, 0, 1, 0, -1}; - for (auto& pos : positions) { - int i = pos[0], j = pos[1]; - if (grid[i][j] == 1) { + vector ans; + for (auto& p : positions) { + int i = p[0], j = p[1]; + if (grid[i][j]) { ans.push_back(cnt); continue; } @@ -233,8 +240,7 @@ public: ++cnt; for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && find(x * n + y) != find(i * n + j)) { - p[find(x * n + y)] = find(i * n + j); + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] && uf.unite(i * n + j, x * n + y)) { --cnt; } } @@ -242,38 +248,58 @@ public: } return ans; } - - int find(int x) { - if (p[x] != x) p[x] = find(p[x]); - return p[x]; - } }; ``` ### **Go** ```go -func numIslands2(m int, n int, positions [][]int) []int { - p := make([]int, m*n) - for i := 0; i < len(p); i++ { +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { + p := make([]int, n) + size := make([]int, n) + for i := range p { p[i] = i + size[i] = 1 + } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) } + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false + } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] + } + return true +} + +func numIslands2(m int, n int, positions [][]int) (ans []int) { + uf := newUnionFind(m * n) grid := make([][]int, m) - for i := 0; i < m; i++ { + for i := range grid { grid[i] = make([]int, n) } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) - } - return p[x] - } - var ans []int + dirs := [5]int{-1, 0, 1, 0, -1} cnt := 0 - dirs := []int{-1, 0, 1, 0, -1} - for _, pos := range positions { - i, j := pos[0], pos[1] + for _, p := range positions { + i, j := p[0], p[1] if grid[i][j] == 1 { ans = append(ans, cnt) continue @@ -282,14 +308,77 @@ func numIslands2(m int, n int, positions [][]int) []int { cnt++ for k := 0; k < 4; k++ { x, y := i+dirs[k], j+dirs[k+1] - if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && find(x*n+y) != find(i*n+j) { - p[find(x*n+y)] = find(i*n + j) + if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && uf.union(i*n+j, x*n+y) { cnt-- } } ans = append(ans, cnt) } - return ans + return +} +``` + +## **TypeScript** + +```ts +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), this.find(b)]; + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } +} + +function numIslands2(m: number, n: number, positions: number[][]): number[] { + const grid: number[][] = Array.from({ length: m }, () => Array(n).fill(0)); + const uf = new UnionFind(m * n); + const ans: number[] = []; + const dirs: number[] = [-1, 0, 1, 0, -1]; + let cnt = 0; + for (const [i, j] of positions) { + if (grid[i][j]) { + ans.push(cnt); + continue; + } + grid[i][j] = 1; + ++cnt; + for (let k = 0; k < 4; ++k) { + const [x, y] = [i + dirs[k], j + dirs[k + 1]]; + if (x < 0 || x >= m || y < 0 || y >= n || !grid[x][y]) { + continue; + } + if (uf.union(i * n + j, x * n + y)) { + --cnt; + } + } + ans.push(cnt); + } + return ans; } ``` diff --git a/solution/0300-0399/0305.Number of Islands II/README_EN.md b/solution/0300-0399/0305.Number of Islands II/README_EN.md index cf7cf5201686a..083a38e15839d 100644 --- a/solution/0300-0399/0305.Number of Islands II/README_EN.md +++ b/solution/0300-0399/0305.Number of Islands II/README_EN.md @@ -49,39 +49,58 @@ Initially, the 2d grid is filled with water. ## Solutions -Union find. +**Solution 1: Union-Find** + +We use a two-dimensional array $grid$ to represent a map, where $0$ and $1$ represent water and land respectively. Initially, all cells in $grid$ are water cells (i.e., all cells are $0$), and we use a variable $cnt$ to record the number of islands. The connectivity between islands can be maintained by a union-find set $uf$. + +Next, we traverse each position $(i, j)$ in the array $positions$. If $grid[i][j]$ is $1$, it means that this position is already land, and we directly add $cnt$ to the answer; otherwise, we change the value of $grid[i][j]$ to $1$, and increase the value of $cnt$ by $1$. Then, we traverse the four directions of up, down, left, and right of this position. If a certain direction is $1$, and this position does not belong to the same connected component as $(i, j)$, then we merge this position with $(i, j)$, and decrease the value of $cnt$ by $1$. After traversing the four directions of up, down, left, and right of this position, we add $cnt$ to the answer. + +The time complexity is $O(k \times \alpha(m \times n))$ or $O(k \times \log(m \times n))$, where $k$ is the length of $positions$, and $\alpha$ is the inverse function of the Ackermann function. In this problem, $\alpha(m \times n)$ can be considered as a very small constant. ### **Python3** ```python +class UnionFind: + def __init__(self, n: int): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x: int): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a: int, b: int) -> bool: + pa, pb = self.find(a - 1), self.find(b - 1) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + class Solution: def numIslands2(self, m: int, n: int, positions: List[List[int]]) -> List[int]: - def find(x): - if p[x] != x: - p[x] = find(p[x]) - return p[x] - + uf = UnionFind(m * n) grid = [[0] * n for _ in range(m)] - cnt = 0 - p = list(range(m * n)) ans = [] + dirs = (-1, 0, 1, 0, -1) + cnt = 0 for i, j in positions: - if grid[i][j] == 1: + if grid[i][j]: ans.append(cnt) continue grid[i][j] = 1 cnt += 1 - for a, b in [[0, -1], [0, 1], [1, 0], [-1, 0]]: + for a, b in pairwise(dirs): x, y = i + a, j + b - if ( - 0 <= x < m - and 0 <= y < n - and grid[x][y] == 1 - and find(i * n + j) != find(x * n + y) - ): - p[find(i * n + j)] = find(x * n + y) + if 0 <= x < m and 0 <= y < n and grid[x][y] and uf.union(i * n + j, x * n + y): cnt -= 1 ans.append(cnt) return ans @@ -90,21 +109,51 @@ class Solution: ### **Java** ```java -class Solution { - private int[] p; - - public List numIslands2(int m, int n, int[][] positions) { - p = new int[m * n]; - for (int i = 0; i < p.length; ++i) { +class UnionFind { + private final int[] p; + private final int[] size; + + public UnionFind(int n) { + p = new int[n]; + size = new int[n]; + for (int i = 0; i < n; ++i) { p[i] = i; + size[i] = 1; } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } +} + +class Solution { + public List numIslands2(int m, int n, int[][] positions) { int[][] grid = new int[m][n]; + UnionFind uf = new UnionFind(m * n); + int[] dirs = {-1, 0, 1, 0, -1}; int cnt = 0; List ans = new ArrayList<>(); - int[] dirs = {-1, 0, 1, 0, -1}; - for (int[] pos : positions) { - int i = pos[0]; - int j = pos[1]; + for (var p : positions) { + int i = p[0], j = p[1]; if (grid[i][j] == 1) { ans.add(cnt); continue; @@ -112,11 +161,9 @@ class Solution { grid[i][j] = 1; ++cnt; for (int k = 0; k < 4; ++k) { - int x = i + dirs[k]; - int y = j + dirs[k + 1]; + int x = i + dirs[k], y = j + dirs[k + 1]; if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 - && find(x * n + y) != find(i * n + j)) { - p[find(x * n + y)] = find(i * n + j); + && uf.union(i * n + j, x * n + y)) { --cnt; } } @@ -124,33 +171,58 @@ class Solution { } return ans; } +} +``` + +### **C++** + +```cpp +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } - private int find(int x) { + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } -} -``` -### **C++** +private: + vector p, size; +}; -```cpp class Solution { public: - vector p; - vector numIslands2(int m, int n, vector>& positions) { - p.resize(m * n); - for (int i = 0; i < p.size(); ++i) p[i] = i; - vector> grid(m, vector(n)); - vector ans; + int grid[m][n]; + memset(grid, 0, sizeof(grid)); + UnionFind uf(m * n); + int dirs[5] = {-1, 0, 1, 0, -1}; int cnt = 0; - vector dirs = {-1, 0, 1, 0, -1}; - for (auto& pos : positions) { - int i = pos[0], j = pos[1]; - if (grid[i][j] == 1) { + vector ans; + for (auto& p : positions) { + int i = p[0], j = p[1]; + if (grid[i][j]) { ans.push_back(cnt); continue; } @@ -158,8 +230,7 @@ public: ++cnt; for (int k = 0; k < 4; ++k) { int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && find(x * n + y) != find(i * n + j)) { - p[find(x * n + y)] = find(i * n + j); + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] && uf.unite(i * n + j, x * n + y)) { --cnt; } } @@ -167,38 +238,58 @@ public: } return ans; } - - int find(int x) { - if (p[x] != x) p[x] = find(p[x]); - return p[x]; - } }; ``` ### **Go** ```go -func numIslands2(m int, n int, positions [][]int) []int { - p := make([]int, m*n) - for i := 0; i < len(p); i++ { +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { + p := make([]int, n) + size := make([]int, n) + for i := range p { p[i] = i + size[i] = 1 + } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) } + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false + } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] + } + return true +} + +func numIslands2(m int, n int, positions [][]int) (ans []int) { + uf := newUnionFind(m * n) grid := make([][]int, m) - for i := 0; i < m; i++ { + for i := range grid { grid[i] = make([]int, n) } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) - } - return p[x] - } - var ans []int + dirs := [5]int{-1, 0, 1, 0, -1} cnt := 0 - dirs := []int{-1, 0, 1, 0, -1} - for _, pos := range positions { - i, j := pos[0], pos[1] + for _, p := range positions { + i, j := p[0], p[1] if grid[i][j] == 1 { ans = append(ans, cnt) continue @@ -207,14 +298,77 @@ func numIslands2(m int, n int, positions [][]int) []int { cnt++ for k := 0; k < 4; k++ { x, y := i+dirs[k], j+dirs[k+1] - if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && find(x*n+y) != find(i*n+j) { - p[find(x*n+y)] = find(i*n + j) + if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && uf.union(i*n+j, x*n+y) { cnt-- } } ans = append(ans, cnt) } - return ans + return +} +``` + +## **TypeScript** + +```ts +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), this.find(b)]; + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } +} + +function numIslands2(m: number, n: number, positions: number[][]): number[] { + const grid: number[][] = Array.from({ length: m }, () => Array(n).fill(0)); + const uf = new UnionFind(m * n); + const ans: number[] = []; + const dirs: number[] = [-1, 0, 1, 0, -1]; + let cnt = 0; + for (const [i, j] of positions) { + if (grid[i][j]) { + ans.push(cnt); + continue; + } + grid[i][j] = 1; + ++cnt; + for (let k = 0; k < 4; ++k) { + const [x, y] = [i + dirs[k], j + dirs[k + 1]]; + if (x < 0 || x >= m || y < 0 || y >= n || !grid[x][y]) { + continue; + } + if (uf.union(i * n + j, x * n + y)) { + --cnt; + } + } + ans.push(cnt); + } + return ans; } ``` diff --git a/solution/0300-0399/0305.Number of Islands II/Solution.cpp b/solution/0300-0399/0305.Number of Islands II/Solution.cpp index dffdd0297c6d0..2175b71fe3448 100644 --- a/solution/0300-0399/0305.Number of Islands II/Solution.cpp +++ b/solution/0300-0399/0305.Number of Islands II/Solution.cpp @@ -1,36 +1,62 @@ -class Solution { -public: - vector p; - - vector numIslands2(int m, int n, vector>& positions) { - p.resize(m * n); - for (int i = 0; i < p.size(); ++i) p[i] = i; - vector> grid(m, vector(n)); - vector ans; - int cnt = 0; - vector dirs = {-1, 0, 1, 0, -1}; - for (auto& pos : positions) { - int i = pos[0], j = pos[1]; - if (grid[i][j] == 1) { - ans.push_back(cnt); - continue; - } - grid[i][j] = 1; - ++cnt; - for (int k = 0; k < 4; ++k) { - int x = i + dirs[k], y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && find(x * n + y) != find(i * n + j)) { - p[find(x * n + y)] = find(i * n + j); - --cnt; - } - } - ans.push_back(cnt); - } - return ans; - } - - int find(int x) { - if (p[x] != x) p[x] = find(p[x]); - return p[x]; - } +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + +private: + vector p, size; +}; + +class Solution { +public: + vector numIslands2(int m, int n, vector>& positions) { + int grid[m][n]; + memset(grid, 0, sizeof(grid)); + UnionFind uf(m * n); + int dirs[5] = {-1, 0, 1, 0, -1}; + int cnt = 0; + vector ans; + for (auto& p : positions) { + int i = p[0], j = p[1]; + if (grid[i][j]) { + ans.push_back(cnt); + continue; + } + grid[i][j] = 1; + ++cnt; + for (int k = 0; k < 4; ++k) { + int x = i + dirs[k], y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] && uf.union(i * n + j, x * n + y)) { + --cnt; + } + } + ans.push_back(cnt); + } + return ans; + } }; \ No newline at end of file diff --git a/solution/0300-0399/0305.Number of Islands II/Solution.go b/solution/0300-0399/0305.Number of Islands II/Solution.go index 8d5415237f054..b0b2d47bd7b16 100644 --- a/solution/0300-0399/0305.Number of Islands II/Solution.go +++ b/solution/0300-0399/0305.Number of Islands II/Solution.go @@ -1,24 +1,49 @@ -func numIslands2(m int, n int, positions [][]int) []int { - p := make([]int, m*n) - for i := 0; i < len(p); i++ { +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { + p := make([]int, n) + size := make([]int, n) + for i := range p { p[i] = i + size[i] = 1 } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) + } + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false + } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] + } + return true +} + +func numIslands2(m int, n int, positions [][]int) (ans []int) { + uf := newUnionFind(m * n) grid := make([][]int, m) - for i := 0; i < m; i++ { + for i := range grid { grid[i] = make([]int, n) } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) - } - return p[x] - } - var ans []int + dirs := [5]int{-1, 0, 1, 0, -1} cnt := 0 - dirs := []int{-1, 0, 1, 0, -1} - for _, pos := range positions { - i, j := pos[0], pos[1] + for _, p := range positions { + i, j := p[0], p[1] if grid[i][j] == 1 { ans = append(ans, cnt) continue @@ -27,12 +52,11 @@ func numIslands2(m int, n int, positions [][]int) []int { cnt++ for k := 0; k < 4; k++ { x, y := i+dirs[k], j+dirs[k+1] - if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && find(x*n+y) != find(i*n+j) { - p[find(x*n+y)] = find(i*n + j) + if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 && uf.union(i*n+j, x*n+y) { cnt-- } } ans = append(ans, cnt) } - return ans + return } \ No newline at end of file diff --git a/solution/0300-0399/0305.Number of Islands II/Solution.java b/solution/0300-0399/0305.Number of Islands II/Solution.java index 8ff3fdacc3d63..e5808e8b70af7 100644 --- a/solution/0300-0399/0305.Number of Islands II/Solution.java +++ b/solution/0300-0399/0305.Number of Islands II/Solution.java @@ -1,42 +1,63 @@ -class Solution { - private int[] p; - - public List numIslands2(int m, int n, int[][] positions) { - p = new int[m * n]; - for (int i = 0; i < p.length; ++i) { - p[i] = i; - } - int[][] grid = new int[m][n]; - int cnt = 0; - List ans = new ArrayList<>(); - int[] dirs = {-1, 0, 1, 0, -1}; - for (int[] pos : positions) { - int i = pos[0]; - int j = pos[1]; - if (grid[i][j] == 1) { - ans.add(cnt); - continue; - } - grid[i][j] = 1; - ++cnt; - for (int k = 0; k < 4; ++k) { - int x = i + dirs[k]; - int y = j + dirs[k + 1]; - if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 - && find(x * n + y) != find(i * n + j)) { - p[find(x * n + y)] = find(i * n + j); - --cnt; - } - } - ans.add(cnt); - } - return ans; - } - - private int find(int x) { - if (p[x] != x) { - p[x] = find(p[x]); - } - return p[x]; - } +class UnionFind { + private final int[] p; + private final int[] size; + + public UnionFind(int n) { + p = new int[n]; + size = new int[n]; + for (int i = 0; i < n; ++i) { + p[i] = i; + size[i] = 1; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } +} + +class Solution { + public List numIslands2(int m, int n, int[][] positions) { + int[][] grid = new int[m][n]; + UnionFind uf = new UnionFind(m * n); + int[] dirs = {-1, 0, 1, 0, -1}; + int cnt = 0; + List ans = new ArrayList<>(); + for (var p : positions) { + int i = p[0], j = p[1]; + if (grid[i][j] == 1) { + ans.add(cnt); + continue; + } + grid[i][j] = 1; + ++cnt; + for (int k = 0; k < 4; ++k) { + int x = i + dirs[k], y = j + dirs[k + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 + && uf.union(i * n + j, x * n + y)) { + --cnt; + } + } + ans.add(cnt); + } + return ans; + } } \ No newline at end of file diff --git a/solution/0300-0399/0305.Number of Islands II/Solution.py b/solution/0300-0399/0305.Number of Islands II/Solution.py index 1e77b98ff21ff..738f6d2ccc4cc 100644 --- a/solution/0300-0399/0305.Number of Islands II/Solution.py +++ b/solution/0300-0399/0305.Number of Islands II/Solution.py @@ -1,27 +1,47 @@ -class Solution: - def numIslands2(self, m: int, n: int, positions: List[List[int]]) -> List[int]: - p = list(range(m * n)) - grid = [[0] * n for _ in range(m)] - - def check(i, j): - return 0 <= i < m and 0 <= j < n and grid[i][j] == 1 - - def find(x): - if p[x] != x: - p[x] = find(p[x]) - return p[x] - - res = [] - cur = 0 - for i, j in positions: - if grid[i][j] == 1: - res.append(cur) - continue - grid[i][j] = 1 - cur += 1 - for x, y in [(-1, 0), (1, 0), (0, -1), (0, 1)]: - if check(i + x, j + y) and find(i * n + j) != find((i + x) * n + j + y): - p[find(i * n + j)] = find((i + x) * n + j + y) - cur -= 1 - res.append(cur) - return res +class UnionFind: + def __init__(self, n: int): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x: int): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a: int, b: int) -> bool: + pa, pb = self.find(a - 1), self.find(b - 1) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + +class Solution: + def numIslands2(self, m: int, n: int, positions: List[List[int]]) -> List[int]: + uf = UnionFind(m * n) + grid = [[0] * n for _ in range(m)] + ans = [] + dirs = (-1, 0, 1, 0, -1) + cnt = 0 + for i, j in positions: + if grid[i][j]: + ans.append(cnt) + continue + grid[i][j] = 1 + cnt += 1 + for a, b in pairwise(dirs): + x, y = i + a, j + b + if ( + 0 <= x < m + and 0 <= y < n + and grid[x][y] + and uf.union(i * n + j, x * n + y) + ): + cnt -= 1 + ans.append(cnt) + return ans diff --git a/solution/0300-0399/0305.Number of Islands II/Solution.ts b/solution/0300-0399/0305.Number of Islands II/Solution.ts new file mode 100644 index 0000000000000..c5de3dbb2d705 --- /dev/null +++ b/solution/0300-0399/0305.Number of Islands II/Solution.ts @@ -0,0 +1,59 @@ +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), this.find(b)]; + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } +} + +function numIslands2(m: number, n: number, positions: number[][]): number[] { + const grid: number[][] = Array.from({ length: m }, () => Array(n).fill(0)); + const uf = new UnionFind(m * n); + const ans: number[] = []; + const dirs: number[] = [-1, 0, 1, 0, -1]; + let cnt = 0; + for (const [i, j] of positions) { + if (grid[i][j]) { + ans.push(cnt); + continue; + } + grid[i][j] = 1; + ++cnt; + for (let k = 0; k < 4; ++k) { + const [x, y] = [i + dirs[k], j + dirs[k + 1]]; + if (x < 0 || x >= m || y < 0 || y >= n || !grid[x][y]) { + continue; + } + if (uf.union(i * n + j, x * n + y)) { + --cnt; + } + } + ans.push(cnt); + } + return ans; +} From 668dde22056066d51d4931d3e164533529d2c5bd Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Fri, 22 Dec 2023 15:36:21 +0800 Subject: [PATCH 2/2] Update README.md --- solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md b/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md index d6b8ea17e8dc7..25fc40cb89adf 100644 --- a/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md +++ b/solution/0300-0399/0304.Range Sum Query 2D - Immutable/README.md @@ -168,7 +168,6 @@ public: ### **Rust** ```rust - /** * Your NumMatrix object will be instantiated and called as such: * let obj = NumMatrix::new(matrix);