Merge branch 'master' of github.com:youngyangyang04/leetcode-master

This commit is contained in:
programmercarl
2024-06-13 10:31:08 +08:00
10 changed files with 184 additions and 21 deletions

View File

@ -403,6 +403,7 @@ class Solution:
```
### Go
(版本一) 双指针
```Go
func threeSum(nums []int) [][]int {
@ -442,6 +443,42 @@ func threeSum(nums []int) [][]int {
return res
}
```
(版本二) 哈希解法
```Go
func threeSum(nums []int) [][]int {
res := make([][]int, 0)
sort.Ints(nums)
// 找出a + b + c = 0
// a = nums[i], b = nums[j], c = -(a + b)
for i := 0; i < len(nums); i++ {
// 排序之后如果第一个元素已经大于零,那么不可能凑成三元组
if nums[i] > 0 {
break
}
// 三元组元素a去重
if i > 0 && nums[i] == nums[i-1] {
continue
}
set := make(map[int]struct{})
for j := i + 1; j < len(nums); j++ {
// 三元组元素b去重
if j > i + 2 && nums[j] == nums[j-1] && nums[j-1] == nums[j-2] {
continue
}
c := -nums[i] - nums[j]
if _, ok := set[c]; ok {
res = append(res, []int{nums[i], nums[j], c})
// 三元组元素c去重
delete(set, c)
} else {
set[nums[j]] = struct{}{}
}
}
}
return res
}
```
### JavaScript:

View File

@ -200,6 +200,66 @@ class Solution {
}
```
```java
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>(); // 存放结果
if (matrix.length == 0 || matrix[0].length == 0)
return res;
int rows = matrix.length, columns = matrix[0].length;
int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
int loop = 0; // 循环次数
int offset = 1; // 每一圈循环,需要控制每一条边遍历的长度
while (loop < Math.min(rows, columns) / 2) {
int i = startx;
int j = starty;
// 模拟填充上行从左到右(左闭右开)
for (; j < columns - offset; j++) {
res.add(matrix[i][j]);
}
// 模拟填充右列从上到下(左闭右开)
for (; i < rows - offset; i++) {
res.add(matrix[i][j]);
}
// 模拟填充下行从右到左(左闭右开)
for (; j > starty; j--) {
res.add(matrix[i][j]);
}
// 模拟填充左列从下到上(左闭右开)
for (; i > startx; i--) {
res.add(matrix[i][j]);
}
// 起始位置加1 循环次数加1 并控制每条边遍历的长度
startx++;
starty++;
offset++;
loop++;
}
// 如果列或行中的最小值为奇数 则一定有未遍历的部分
// 可以自行画图理解
if (Math.min(rows, columns) % 2 == 1) {
// 当行大于列时 未遍历的部分是列
// (startx, starty)即下一个要遍历位置 从该位置出发 遍历完未遍历的列
// 遍历次数为rows - columns + 1
if (rows > columns) {
for (int i = 0; i < rows - columns + 1; i++) {
res.add(matrix[startx++][starty]);
}
} else {
// 此处与上面同理 遍历完未遍历的行
for (int i = 0; i < columns - rows + 1; i++) {
res.add(matrix[startx][starty++]);
}
}
}
return res;
}
}
```
### Javascript
```
/**

View File

@ -201,7 +201,7 @@ class Solution:
return result
```
```python
# 递归法
#递归法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
@ -210,18 +210,24 @@ class Solution:
# self.right = right
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
levels = []
self.helper(root, 0, levels)
def traverse(node, level):
if not node:
return
if len(levels) == level:
levels.append([])
levels[level].append(node.val)
traverse(node.left, level + 1)
traverse(node.right, level + 1)
traverse(root, 0)
return levels
def helper(self, node, level, levels):
if not node:
return
if len(levels) == level:
levels.append([])
levels[level].append(node.val)
self.helper(node.left, level + 1, levels)
self.helper(node.right, level + 1, levels)
```

View File

@ -26,7 +26,7 @@
## 算法公开课
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[把环形链表讲清楚!| LeetCode:142.环形链表II](https://www.bilibili.com/video/BV1if4y1d7ob),相信结合视频看本篇题解,更有助于大家对链表的理解。**
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[把环形链表讲清楚!| LeetCode:142.环形链表II](https://www.bilibili.com/video/BV1if4y1d7ob),相信结合视频看本篇题解,更有助于大家对链表的理解。**
## 思路

View File

@ -54,7 +54,7 @@
1. 首先定义 一个unordered_mapkey放a和b两数之和value 放a和b两数之和出现的次数。
2. 遍历大A和大B数组统计两个数组元素之和和出现的次数放到map中。
3. 定义int变量count用来统计 a+b+c+d = 0 出现的次数。
4. 遍历大C和大D数组找到如果 0-(c+d) 在map中出现过的话就用count把map中key对应的value也就是出现次数统计出来。
4. 遍历大C和大D数组找到如果 0-(c+d) 在map中出现过的话就用count把map中key对应的value也就是出现次数统计出来。
5. 最后返回统计值 count 就可以了
C++代码:
@ -71,7 +71,7 @@ public:
}
}
int count = 0; // 统计a+b+c+d = 0 出现的次数
// 遍历大C和大D数组找到如果 0-(c+d) 在map中出现过的话就把map中key对应的value也就是出现次数统计出来。
// 遍历大C和大D数组找到如果 0-(c+d) 在map中出现过的话就把map中key对应的value也就是出现次数统计出来。
for (int c : C) {
for (int d : D) {
if (umap.find(0 - (c + d)) != umap.end()) {

View File

@ -403,6 +403,18 @@ func repeatedSubstringPattern(s string) bool {
}
```
移动匹配
```go
func repeatedSubstringPattern(s string) bool {
if len(s) == 0 {
return false
}
t := s + s
return strings.Contains(t[1:len(t)-1], s)
}
```
### JavaScript:
> 前缀表统一减一

View File

@ -395,7 +395,7 @@ class Solution {
深度优先遍历
```Python3
```Python
class Solution:
def __init__(self):
self.position = [[-1, 0], [0, 1], [1, 0], [0, -1]] # 四个方向
@ -442,7 +442,7 @@ class Solution:
广度优先遍历
```Python3
```Python
class Solution:
def __init__(self):
self.position = [[-1, 0], [0, 1], [1, 0], [0, -1]] # 四个方向

View File

@ -38,11 +38,22 @@ void init() {
father[i] = i;
}
}
// 并查集里寻根的过程
// 并查集里寻根的过程,这里递归调用当题目数据过多,递归调用可能会发生栈溢出
int find(int u) {
return u == father[u] ? u : father[u] = find(father[u]); // 路径压缩
}
// 使用迭代的方法可以避免栈溢出问题
int find(int x) {
while (x != parent[x]) {
// 路径压缩直接将x链接到其祖先节点减少树的高度
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
// 判断 u 和 v是否找到同一个根
bool isSame(int u, int v) {
u = find(u);
@ -75,6 +86,8 @@ void join(int u, int v) {
此时我们就可以直接套用并查集模板。
本题在join函数调用find函数时如果是递归调用会发生栈溢出提示建议使用迭代方法
使用 join(int u, int v)将每条边加入到并查集。
最后 isSame(int u, int v) 判断是否是同一个根 就可以了。
@ -93,8 +106,13 @@ private:
}
}
// 并查集里寻根的过程
int find(int u) {
return u == father[u] ? u : father[u] = find(father[u]);
int find(int x) {
while (x != parent[x]) {
// 路径压缩直接将x链接到其祖先节点减少树的高度
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
// 判断 u 和 v是否找到同一个根

View File

@ -295,7 +295,37 @@ int main()
```
### JavaScript
```javascript
// JS中字符串内不可单独修改
// 右旋转
function reverseLeftWords(s, k) {
const reverse = (sList, start, end) => {
for (let i = start, j = end; i < j; i++, j--) {
[sList[i], sList[j]] = [sList[j], sList[i]];
}
}
const sList = Array.from(s);
reverse(sList, 0, sList.length - k - 1);
reverse(sList, sList.length - k, sList.length - 1);
reverse(sList, 0, sList.length - 1);
return sList.join('');
}
// 左旋转
var reverseLeftWords = function(s, n) {
const reverse = (sList, start, end) => {
for (let i = start, j = end; i < j; i++, j--) {
[sList[i], sList[j]] = [sList[j], sList[i]];
}
}
const sList = s.split('');
reverse(sList, 0, n - 1);
reverse(sList, n, sList.length - 1);
reverse(sList, 0, sList.length - 1);
return sList.join('');
};
```
### TypeScript

View File

@ -117,7 +117,7 @@ public:
### 后序遍历(迭代法)
再来看后序遍历,先序遍历是中左右,后遍历是左右中那么我们只需要调整一下先序遍历的代码顺序就变成中右左的遍历顺序然后在反转result数组输出的结果顺序就是左右中了如下图
再来看后序遍历,先序遍历是中左右,后遍历是左右中那么我们只需要调整一下先序遍历的代码顺序就变成中右左的遍历顺序然后在反转result数组输出的结果顺序就是左右中了如下图
![前序到后序](https://code-thinking-1253855093.file.myqcloud.com/pics/20200808200338924.png)
@ -153,7 +153,7 @@ public:
上面这句话,可能一些同学不太理解,建议自己亲手用迭代法,先写出来前序,再试试能不能写出中序,就能理解了。
**那么问题又来了,难道 二叉树前后中序遍历的迭代法实现,就不能风格统一么(即前序遍历 改变代码顺序就可以实现中序 和 后序)?**
**那么问题又来了,难道二叉树前后中序遍历的迭代法实现,就不能风格统一么(即前序遍历改变代码顺序就可以实现中序 和 后序)?**
当然可以,这种写法,还不是很好理解,我们将在下一篇文章里重点讲解,敬请期待!