From 8620f4e4c8de64e42da6fdba53db8dee489abace Mon Sep 17 00:00:00 2001 From: yanglbme Date: Thu, 14 Dec 2023 16:53:55 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1901 No.1901.Find a Peak Element II --- .../1901.Find a Peak Element II/README.md | 154 +++++++++++++++++- .../1901.Find a Peak Element II/README_EN.md | 154 +++++++++++++++++- .../1901.Find a Peak Element II/Solution.cpp | 17 ++ .../1901.Find a Peak Element II/Solution.go | 22 +++ .../1901.Find a Peak Element II/Solution.java | 26 +++ .../1901.Find a Peak Element II/Solution.py | 11 ++ .../1901.Find a Peak Element II/Solution.rs | 23 +++ .../1901.Find a Peak Element II/Solution.ts | 13 ++ 8 files changed, 418 insertions(+), 2 deletions(-) create mode 100644 solution/1900-1999/1901.Find a Peak Element II/Solution.cpp create mode 100644 solution/1900-1999/1901.Find a Peak Element II/Solution.go create mode 100644 solution/1900-1999/1901.Find a Peak Element II/Solution.java create mode 100644 solution/1900-1999/1901.Find a Peak Element II/Solution.py create mode 100644 solution/1900-1999/1901.Find a Peak Element II/Solution.rs create mode 100644 solution/1900-1999/1901.Find a Peak Element II/Solution.ts diff --git a/solution/1900-1999/1901.Find a Peak Element II/README.md b/solution/1900-1999/1901.Find a Peak Element II/README.md index a37ebb5c60b8a..18fcae226ba99 100644 --- a/solution/1900-1999/1901.Find a Peak Element II/README.md +++ b/solution/1900-1999/1901.Find a Peak Element II/README.md @@ -54,6 +54,28 @@ +**方法一:二分查找** + +记 $m$ 和 $n$ 分别为矩阵的行数和列数。 + +题目要求我们寻找峰值,并且时间复杂度为 $O(m \times \log n)$ 或 $O(n \times \log m)$,那么我们可以考虑使用二分查找。 + +我们考虑第 $i$ 行的最大值,不妨将其下标记为 $j$。 + +如果 $mat[i][j] \gt mat[i + 1][j]$,那么第 $[0,..i]$ 行中必然存在一个峰值,我们只需要在第 $[0,..i]$ 行中找到最大值即可。同理,如果 $mat[i][j] \lt mat[i + 1][j]$,那么第 $[i + 1,..m - 1]$ 行中必然存在一个峰值,我们只需要在第 $[i + 1,..m - 1]$ 行中找到最大值即可。 + +为什么上述做法是对的?我们不妨用反证法来证明。 + +如果 $mat[i][j] \gt mat[i + 1][j]$,假设第 $[0,..i]$ 行中不存在峰值,那么 $mat[i][j]$ 不是峰值,而由于 $mat[i][j]$ 是第 $i$ 行的最大值,并且 $mat[i][j] \gt mat[i + 1][j]$,那么 $mat[i][j] \lt mat[i - 1][j]$。我们继续从第 $i - 1$ 行往上考虑,每一行的最大值都小于上一行的最大值。那么当遍历到 $i = 0$ 时,由于矩阵中的元素都是正整数,并且矩阵周边一圈的格子的值都为 $-1$。因此,在第 $0$ 行时,其最大值大于其所有相邻元素,那么第 $0$ 行的最大值就是峰值,与假设矛盾。因此,第 $[0,..i]$ 行中必然存在一个峰值。 + +对于 $mat[i][j] \lt mat[i + 1][j]$ 的情况,我们可以用类似的方法证明第 $[i + 1,..m - 1]$ 行中必然存在一个峰值。 + +因此,我们可以使用二分查找来寻找峰值。 + +我们二分查找矩阵的行,初始时查找的边界为 $l = 0$, $r = m - 1$。每一次,我们找到当前的中间行 $mid$,并找到该行的最大值下标 $j$。如果 $mat[mid][j] \gt mat[mid + 1][j]$,那么我们就在第 $[0,..mid]$ 行中寻找峰值,即更新 $r = mid$。否则,我们就在第 $[mid + 1,..m - 1]$ 行中寻找峰值,即更新 $l = mid + 1$。当 $l = r$ 时,我们就找到了峰值所在的位置 $[l, j_l]$。其中 $j_l$ 是第 $l$ 行的最大值下标。 + +时间复杂度 $O(n \times \log m)$,其中 $m$ 和 $n$ 分别为矩阵的行数和列数。二分查找的时间复杂度为 $O(\log m)$,每次二分查找时,我们需要遍历第 $mid$ 行的所有元素,时间复杂度为 $O(n)$。空间复杂度 $O(1)$。 + ### **Python3** @@ -61,7 +83,17 @@ ```python - +class Solution: + def findPeakGrid(self, mat: List[List[int]]) -> List[int]: + l, r = 0, len(mat) - 1 + while l < r: + mid = (l + r) >> 1 + j = mat[mid].index(max(mat[mid])) + if mat[mid][j] > mat[mid + 1][j]: + r = mid + else: + l = mid + 1 + return [l, mat[l].index(max(mat[l]))] ``` ### **Java** @@ -69,7 +101,127 @@ ```java +class Solution { + public int[] findPeakGrid(int[][] mat) { + int l = 0, r = mat.length - 1; + int n = mat[0].length; + while (l < r) { + int mid = (l + r) >> 1; + int j = maxPos(mat[mid]); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + return new int[] {l, maxPos(mat[l])}; + } + + private int maxPos(int[] arr) { + int j = 0; + for (int i = 1; i < arr.length; ++i) { + if (arr[j] < arr[i]) { + j = i; + } + } + return j; + } +} +``` + +### **C++** + +```cpp +class Solution { +public: + vector findPeakGrid(vector>& mat) { + int l = 0, r = mat.size() - 1; + while (l < r) { + int mid = (l + r) >> 1; + int j = distance(mat[mid].begin(), max_element(mat[mid].begin(), mat[mid].end())); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + int j = distance(mat[l].begin(), max_element(mat[l].begin(), mat[l].end())); + return {l, j}; + } +}; +``` + +### **Go** + +```go +func findPeakGrid(mat [][]int) []int { + maxPos := func(arr []int) int { + j := 0 + for i := 1; i < len(arr); i++ { + if arr[i] > arr[j] { + j = i + } + } + return j + } + l, r := 0, len(mat)-1 + for l < r { + mid := (l + r) >> 1 + j := maxPos(mat[mid]) + if mat[mid][j] > mat[mid+1][j] { + r = mid + } else { + l = mid + 1 + } + } + return []int{l, maxPos(mat[l])} +} +``` + +### **TypeScript** + +```ts +function findPeakGrid(mat: number[][]): number[] { + let [l, r] = [0, mat.length - 1]; + while (l < r) { + const mid = (l + r) >> 1; + const j = mat[mid].indexOf(Math.max(...mat[mid])); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + return [l, mat[l].indexOf(Math.max(...mat[l]))]; +} +``` +### **Rust** + +```rust +impl Solution { + pub fn find_peak_grid(mat: Vec>) -> Vec { + let mut l: usize = 0; + let mut r: usize = mat.len() - 1; + while l < r { + let mid: usize = (l + r) >> 1; + let j: usize = mat[mid] + .iter() + .position(|&x| x == *mat[mid].iter().max().unwrap()) + .unwrap(); + if mat[mid][j] > mat[mid + 1][j] { + r = mid; + } else { + l = mid + 1; + } + } + let j: usize = mat[l] + .iter() + .position(|&x| x == *mat[l].iter().max().unwrap()) + .unwrap(); + vec![l as i32, j as i32] + } +} ``` ### **...** diff --git a/solution/1900-1999/1901.Find a Peak Element II/README_EN.md b/solution/1900-1999/1901.Find a Peak Element II/README_EN.md index f1652c8c37a10..b68f7bb90ed3e 100644 --- a/solution/1900-1999/1901.Find a Peak Element II/README_EN.md +++ b/solution/1900-1999/1901.Find a Peak Element II/README_EN.md @@ -46,18 +46,170 @@ ## Solutions +**Solution 1: Binary Search** + +Let $m$ and $n$ be the number of rows and columns of the matrix, respectively. + +The problem asks us to find a peak, and the time complexity should be $O(m \times \log n)$ or $O(n \times \log m)$. Therefore, we can consider using binary search. + +We consider the maximum value of the $i$-th row, and denote its index as $j$. + +If $mat[i][j] > mat[i + 1][j]$, then there must be a peak in the rows $[0,..i]$. We only need to find the maximum value in these rows. Similarly, if $mat[i][j] < mat[i + 1][j]$, then there must be a peak in the rows $[i + 1,..m - 1]$. We only need to find the maximum value in these rows. + +Why is the above method correct? We can prove it by contradiction. + +If $mat[i][j] > mat[i + 1][j]$, suppose there is no peak in the rows $[0,..i]$. Then $mat[i][j]$ is not a peak. Since $mat[i][j]$ is the maximum value of the $i$-th row, and $mat[i][j] > mat[i + 1][j]$, then $mat[i][j] < mat[i - 1][j]$. We continue to consider from the $(i - 1)$-th row upwards, and the maximum value of each row is less than the maximum value of the previous row. When we traverse to $i = 0$, since all elements in the matrix are positive integers, and the values of the cells around the matrix are $-1$. Therefore, at the 0-th row, its maximum value is greater than all its adjacent elements, so the maximum value of the 0-th row is a peak, which contradicts the assumption. Therefore, there must be a peak in the rows $[0,..i]$. + +For the case where $mat[i][j] < mat[i + 1][j]$, we can prove in a similar way that there must be a peak in the rows $[i + 1,..m - 1]$. + +Therefore, we can use binary search to find the peak. + +We perform binary search on the rows of the matrix, initially with the search boundaries $l = 0$, $r = m - 1$. Each time, we find the middle row $mid$ and find the index $j$ of the maximum value of this row. If $mat[mid][j] > mat[mid + 1][j]$, then we search for the peak in the rows $[0,..mid]$, i.e., update $r = mid$. Otherwise, we search for the peak in the rows $[mid + 1,..m - 1]$, i.e., update $l = mid + 1$. When $l = r$, we find the position $[l, j_l]$ of the peak, where $j_l$ is the index of the maximum value of the $l$-th row. + +The time complexity is $O(n \times \log m)$, where $m$ and $n$ are the number of rows and columns of the matrix, respectively. The time complexity of binary search is $O(\log m)$, and each time we perform binary search, we need to traverse all elements of the $mid$-th row, with a time complexity of $O(n)$. The space complexity is $O(1)$. + ### **Python3** ```python - +class Solution: + def findPeakGrid(self, mat: List[List[int]]) -> List[int]: + l, r = 0, len(mat) - 1 + while l < r: + mid = (l + r) >> 1 + j = mat[mid].index(max(mat[mid])) + if mat[mid][j] > mat[mid + 1][j]: + r = mid + else: + l = mid + 1 + return [l, mat[l].index(max(mat[l]))] ``` ### **Java** ```java +class Solution { + public int[] findPeakGrid(int[][] mat) { + int l = 0, r = mat.length - 1; + int n = mat[0].length; + while (l < r) { + int mid = (l + r) >> 1; + int j = maxPos(mat[mid]); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + return new int[] {l, maxPos(mat[l])}; + } + + private int maxPos(int[] arr) { + int j = 0; + for (int i = 1; i < arr.length; ++i) { + if (arr[j] < arr[i]) { + j = i; + } + } + return j; + } +} +``` + +### **C++** + +```cpp +class Solution { +public: + vector findPeakGrid(vector>& mat) { + int l = 0, r = mat.size() - 1; + while (l < r) { + int mid = (l + r) >> 1; + int j = distance(mat[mid].begin(), max_element(mat[mid].begin(), mat[mid].end())); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + int j = distance(mat[l].begin(), max_element(mat[l].begin(), mat[l].end())); + return {l, j}; + } +}; +``` + +### **Go** + +```go +func findPeakGrid(mat [][]int) []int { + maxPos := func(arr []int) int { + j := 0 + for i := 1; i < len(arr); i++ { + if arr[i] > arr[j] { + j = i + } + } + return j + } + l, r := 0, len(mat)-1 + for l < r { + mid := (l + r) >> 1 + j := maxPos(mat[mid]) + if mat[mid][j] > mat[mid+1][j] { + r = mid + } else { + l = mid + 1 + } + } + return []int{l, maxPos(mat[l])} +} +``` + +### **TypeScript** + +```ts +function findPeakGrid(mat: number[][]): number[] { + let [l, r] = [0, mat.length - 1]; + while (l < r) { + const mid = (l + r) >> 1; + const j = mat[mid].indexOf(Math.max(...mat[mid])); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + return [l, mat[l].indexOf(Math.max(...mat[l]))]; +} +``` +### **Rust** + +```rust +impl Solution { + pub fn find_peak_grid(mat: Vec>) -> Vec { + let mut l: usize = 0; + let mut r: usize = mat.len() - 1; + while l < r { + let mid: usize = (l + r) >> 1; + let j: usize = mat[mid] + .iter() + .position(|&x| x == *mat[mid].iter().max().unwrap()) + .unwrap(); + if mat[mid][j] > mat[mid + 1][j] { + r = mid; + } else { + l = mid + 1; + } + } + let j: usize = mat[l] + .iter() + .position(|&x| x == *mat[l].iter().max().unwrap()) + .unwrap(); + vec![l as i32, j as i32] + } +} ``` ### **...** diff --git a/solution/1900-1999/1901.Find a Peak Element II/Solution.cpp b/solution/1900-1999/1901.Find a Peak Element II/Solution.cpp new file mode 100644 index 0000000000000..4d6ba81b29814 --- /dev/null +++ b/solution/1900-1999/1901.Find a Peak Element II/Solution.cpp @@ -0,0 +1,17 @@ +class Solution { +public: + vector findPeakGrid(vector>& mat) { + int l = 0, r = mat.size() - 1; + while (l < r) { + int mid = (l + r) >> 1; + int j = distance(mat[mid].begin(), max_element(mat[mid].begin(), mat[mid].end())); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + int j = distance(mat[l].begin(), max_element(mat[l].begin(), mat[l].end())); + return {l, j}; + } +}; \ No newline at end of file diff --git a/solution/1900-1999/1901.Find a Peak Element II/Solution.go b/solution/1900-1999/1901.Find a Peak Element II/Solution.go new file mode 100644 index 0000000000000..b18b1e0951893 --- /dev/null +++ b/solution/1900-1999/1901.Find a Peak Element II/Solution.go @@ -0,0 +1,22 @@ +func findPeakGrid(mat [][]int) []int { + maxPos := func(arr []int) int { + j := 0 + for i := 1; i < len(arr); i++ { + if arr[i] > arr[j] { + j = i + } + } + return j + } + l, r := 0, len(mat)-1 + for l < r { + mid := (l + r) >> 1 + j := maxPos(mat[mid]) + if mat[mid][j] > mat[mid+1][j] { + r = mid + } else { + l = mid + 1 + } + } + return []int{l, maxPos(mat[l])} +} \ No newline at end of file diff --git a/solution/1900-1999/1901.Find a Peak Element II/Solution.java b/solution/1900-1999/1901.Find a Peak Element II/Solution.java new file mode 100644 index 0000000000000..17b72a4b27882 --- /dev/null +++ b/solution/1900-1999/1901.Find a Peak Element II/Solution.java @@ -0,0 +1,26 @@ +class Solution { + public int[] findPeakGrid(int[][] mat) { + int l = 0, r = mat.length - 1; + int n = mat[0].length; + while (l < r) { + int mid = (l + r) >> 1; + int j = maxPos(mat[mid]); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + return new int[] {l, maxPos(mat[l])}; + } + + private int maxPos(int[] arr) { + int j = 0; + for (int i = 1; i < arr.length; ++i) { + if (arr[j] < arr[i]) { + j = i; + } + } + return j; + } +} \ No newline at end of file diff --git a/solution/1900-1999/1901.Find a Peak Element II/Solution.py b/solution/1900-1999/1901.Find a Peak Element II/Solution.py new file mode 100644 index 0000000000000..cd85b3a0e093a --- /dev/null +++ b/solution/1900-1999/1901.Find a Peak Element II/Solution.py @@ -0,0 +1,11 @@ +class Solution: + def findPeakGrid(self, mat: List[List[int]]) -> List[int]: + l, r = 0, len(mat) - 1 + while l < r: + mid = (l + r) >> 1 + j = mat[mid].index(max(mat[mid])) + if mat[mid][j] > mat[mid + 1][j]: + r = mid + else: + l = mid + 1 + return [l, mat[l].index(max(mat[l]))] diff --git a/solution/1900-1999/1901.Find a Peak Element II/Solution.rs b/solution/1900-1999/1901.Find a Peak Element II/Solution.rs new file mode 100644 index 0000000000000..14d9719089bc6 --- /dev/null +++ b/solution/1900-1999/1901.Find a Peak Element II/Solution.rs @@ -0,0 +1,23 @@ +impl Solution { + pub fn find_peak_grid(mat: Vec>) -> Vec { + let mut l: usize = 0; + let mut r: usize = mat.len() - 1; + while l < r { + let mid: usize = (l + r) >> 1; + let j: usize = mat[mid] + .iter() + .position(|&x| x == *mat[mid].iter().max().unwrap()) + .unwrap(); + if mat[mid][j] > mat[mid + 1][j] { + r = mid; + } else { + l = mid + 1; + } + } + let j: usize = mat[l] + .iter() + .position(|&x| x == *mat[l].iter().max().unwrap()) + .unwrap(); + vec![l as i32, j as i32] + } +} diff --git a/solution/1900-1999/1901.Find a Peak Element II/Solution.ts b/solution/1900-1999/1901.Find a Peak Element II/Solution.ts new file mode 100644 index 0000000000000..8887700879d86 --- /dev/null +++ b/solution/1900-1999/1901.Find a Peak Element II/Solution.ts @@ -0,0 +1,13 @@ +function findPeakGrid(mat: number[][]): number[] { + let [l, r] = [0, mat.length - 1]; + while (l < r) { + const mid = (l + r) >> 1; + const j = mat[mid].indexOf(Math.max(...mat[mid])); + if (mat[mid][j] > mat[mid + 1][j]) { + r = mid; + } else { + l = mid + 1; + } + } + return [l, mat[l].indexOf(Math.max(...mat[l]))]; +}