mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-06 23:28:29 +08:00
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
@ -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:
|
||||
|
||||
|
@ -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
|
||||
```
|
||||
/**
|
||||
|
@ -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)
|
||||
|
||||
```
|
||||
|
||||
|
@ -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),相信结合视频再看本篇题解,更有助于大家对链表的理解。**
|
||||
|
||||
## 思路
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
||||
1. 首先定义 一个unordered_map,key放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()) {
|
||||
|
@ -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:
|
||||
|
||||
> 前缀表统一减一
|
||||
|
@ -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]] # 四个方向
|
||||
|
@ -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是否找到同一个根
|
||||
|
@ -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:
|
||||
|
||||
|
@ -117,7 +117,7 @@ public:
|
||||
|
||||
### 后序遍历(迭代法)
|
||||
|
||||
再来看后序遍历,先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了,如下图:
|
||||
再来看后序遍历,先序遍历是中左右,后序遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了,如下图:
|
||||
|
||||

|
||||
|
||||
@ -153,7 +153,7 @@ public:
|
||||
|
||||
上面这句话,可能一些同学不太理解,建议自己亲手用迭代法,先写出来前序,再试试能不能写出中序,就能理解了。
|
||||
|
||||
**那么问题又来了,难道 二叉树前后中序遍历的迭代法实现,就不能风格统一么(即前序遍历 改变代码顺序就可以实现中序 和 后序)?**
|
||||
**那么问题又来了,难道二叉树前后中序遍历的迭代法实现,就不能风格统一么(即前序遍历改变代码顺序就可以实现中序 和 后序)?**
|
||||
|
||||
当然可以,这种写法,还不是很好理解,我们将在下一篇文章里重点讲解,敬请期待!
|
||||
|
||||
|
Reference in New Issue
Block a user