mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 00:43:04 +08:00
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
@ -268,6 +268,34 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
/**
|
||||
* 递归法(思路来自二叉树最大深度的递归法)
|
||||
* 该题求最小深度,最小深度为根节点到叶子节点的深度,所以在迭代到每个叶子节点时更新最小值。
|
||||
*/
|
||||
int depth = 0;
|
||||
// 定义最小深度,初始化最大值
|
||||
int minDepth = Integer.MAX_VALUE;
|
||||
public int minDepth(TreeNode root) {
|
||||
dep(root);
|
||||
return minDepth == Integer.MAX_VALUE ? 0 : minDepth;
|
||||
}
|
||||
void dep(TreeNode root){
|
||||
if(root == null) return ;
|
||||
// 递归开始,深度增加
|
||||
depth++;
|
||||
dep(root.left);
|
||||
dep(root.right);
|
||||
// 该位置表示递归到叶子节点了,需要更新最小深度minDepth
|
||||
if(root.left == null && root.right == null)
|
||||
minDepth = Math.min(minDepth , depth);
|
||||
// 递归结束,深度减小
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```Java
|
||||
class Solution {
|
||||
/**
|
||||
|
@ -652,62 +652,100 @@ function findItinerary(tickets: string[][]): string[] {
|
||||
### C
|
||||
|
||||
```C
|
||||
char **result;
|
||||
bool *used;
|
||||
int g_found;
|
||||
typedef struct {
|
||||
char *name; /* key */
|
||||
int cnt; /* 记录到达机场是否飞过了 */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} to_airport_t;
|
||||
|
||||
int cmp(const void *str1, const void *str2)
|
||||
{
|
||||
const char **tmp1 = *(char**)str1;
|
||||
const char **tmp2 = *(char**)str2;
|
||||
int ret = strcmp(tmp1[0], tmp2[0]);
|
||||
if (ret == 0) {
|
||||
return strcmp(tmp1[1], tmp2[1]);
|
||||
typedef struct {
|
||||
char *name; /* key */
|
||||
to_airport_t *to_airports;
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} from_airport_t;
|
||||
|
||||
void to_airport_destroy(to_airport_t *airports) {
|
||||
to_airport_t *airport, *tmp;
|
||||
HASH_ITER(hh, airports, airport, tmp) {
|
||||
HASH_DEL(airports, airport);
|
||||
free(airport);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void backtracting(char *** tickets, int ticketsSize, int* returnSize, char *start, char **result, bool *used)
|
||||
{
|
||||
if (*returnSize == ticketsSize + 1) {
|
||||
g_found = 1;
|
||||
return;
|
||||
void from_airport_destroy(from_airport_t *airports) {
|
||||
from_airport_t *airport, *tmp;
|
||||
HASH_ITER(hh, airports, airport, tmp) {
|
||||
to_airport_destroy(airport->to_airports);
|
||||
HASH_DEL(airports, airport);
|
||||
free(airport);
|
||||
}
|
||||
}
|
||||
|
||||
int name_sort(to_airport_t *a, to_airport_t *b) {
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
bool backtracking(from_airport_t *airports, int target_path_len, char **path,
|
||||
int path_len) {
|
||||
if (path_len == target_path_len) return true;
|
||||
|
||||
from_airport_t *from_airport = NULL;
|
||||
HASH_FIND_STR(airports, path[path_len - 1], from_airport);
|
||||
if (!from_airport) return false;
|
||||
|
||||
for (to_airport_t *to_airport = from_airport->to_airports;
|
||||
to_airport != NULL; to_airport = to_airport->hh.next) {
|
||||
if (to_airport->cnt == 0) continue;
|
||||
to_airport->cnt--;
|
||||
path[path_len] = to_airport->name;
|
||||
if (backtracking(airports, target_path_len, path, path_len + 1))
|
||||
return true;
|
||||
to_airport->cnt++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char **findItinerary(char ***tickets, int ticketsSize, int *ticketsColSize,
|
||||
int *returnSize) {
|
||||
from_airport_t *airports = NULL;
|
||||
|
||||
// 记录映射关系
|
||||
for (int i = 0; i < ticketsSize; i++) {
|
||||
if ((used[i] == false) && (strcmp(start, tickets[i][0]) == 0)) {
|
||||
result[*returnSize] = (char*)malloc(sizeof(char) * 4);
|
||||
memcpy(result[*returnSize], tickets[i][1], sizeof(char) * 4);
|
||||
(*returnSize)++;
|
||||
used[i] = true;
|
||||
/*if ((*returnSize) == ticketsSize + 1) {
|
||||
return;
|
||||
}*/
|
||||
backtracting(tickets, ticketsSize, returnSize, tickets[i][1], result, used);
|
||||
if (g_found) {
|
||||
return;
|
||||
}
|
||||
(*returnSize)--;
|
||||
used[i] = false;
|
||||
from_airport_t *from_airport = NULL;
|
||||
to_airport_t *to_airport = NULL;
|
||||
HASH_FIND_STR(airports, tickets[i][0], from_airport);
|
||||
if (!from_airport) {
|
||||
from_airport = malloc(sizeof(from_airport_t));
|
||||
from_airport->name = tickets[i][0];
|
||||
from_airport->to_airports = NULL;
|
||||
HASH_ADD_KEYPTR(hh, airports, from_airport->name,
|
||||
strlen(from_airport->name), from_airport);
|
||||
}
|
||||
HASH_FIND_STR(from_airport->to_airports, tickets[i][1], to_airport);
|
||||
if (!to_airport) {
|
||||
to_airport = malloc(sizeof(to_airport_t));
|
||||
to_airport->name = tickets[i][1];
|
||||
to_airport->cnt = 0;
|
||||
HASH_ADD_KEYPTR(hh, from_airport->to_airports, to_airport->name,
|
||||
strlen(to_airport->name), to_airport);
|
||||
}
|
||||
to_airport->cnt++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
char ** findItinerary(char *** tickets, int ticketsSize, int* ticketsColSize, int* returnSize){
|
||||
if (tickets == NULL || ticketsSize <= 0) {
|
||||
return NULL;
|
||||
// 机场排序
|
||||
for (from_airport *from_airport = airports; from_airport != NULL;
|
||||
from_airport = from_airport->hh.next) {
|
||||
HASH_SRT(hh, from_airport->to_airports, name_sort);
|
||||
}
|
||||
result = malloc(sizeof(char*) * (ticketsSize + 1));
|
||||
used = malloc(sizeof(bool) * ticketsSize);
|
||||
memset(used, false, sizeof(bool) * ticketsSize);
|
||||
result[0] = malloc(sizeof(char) * 4);
|
||||
memcpy(result[0], "JFK", sizeof(char) * 4);
|
||||
g_found = 0;
|
||||
*returnSize = 1;
|
||||
qsort(tickets, ticketsSize, sizeof(tickets[0]), cmp);
|
||||
backtracting(tickets, ticketsSize, returnSize, "JFK", result, used);
|
||||
|
||||
char **path = malloc(sizeof(char *) * (ticketsSize + 1));
|
||||
path[0] = "JFK"; // 起始机场
|
||||
backtracking(airports, ticketsSize + 1, path, 1);
|
||||
|
||||
from_airport_destroy(airports);
|
||||
|
||||
*returnSize = ticketsSize + 1;
|
||||
return result;
|
||||
return path;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -193,7 +193,7 @@ class Solution {
|
||||
class Solution {
|
||||
public int[] topKFrequent(int[] nums, int k) {
|
||||
// 优先级队列,为了避免复杂 api 操作,pq 存储数组
|
||||
// lambda 表达式设置优先级队列从大到小存储 o1 - o2 为从大到小,o2 - o1 反之
|
||||
// lambda 表达式设置优先级队列从大到小存储 o1 - o2 为从小到大,o2 - o1 反之
|
||||
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
|
||||
int[] res = new int[k]; // 答案数组为 k 个元素
|
||||
Map<Integer, Integer> map = new HashMap<>(); // 记录元素出现次数
|
||||
@ -204,6 +204,7 @@ class Solution {
|
||||
tmp[0] = x.getKey();
|
||||
tmp[1] = x.getValue();
|
||||
pq.offer(tmp);
|
||||
// 下面的代码是根据小根堆实现的,我只保留优先队列的最后的k个,只要超出了k我就将最小的弹出,剩余的k个就是答案
|
||||
if(pq.size() > k) {
|
||||
pq.poll();
|
||||
}
|
||||
|
@ -135,7 +135,64 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
### Java:
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
|
||||
int[] father;
|
||||
public boolean validPath(int n, int[][] edges, int source, int destination) {
|
||||
father = new int[n];
|
||||
init();
|
||||
for (int i = 0; i < edges.length; i++) {
|
||||
join(edges[i][0], edges[i][1]);
|
||||
}
|
||||
|
||||
return isSame(source, destination);
|
||||
}
|
||||
|
||||
// 并查集初始化
|
||||
public void init() {
|
||||
for (int i = 0; i < father.length; i++) {
|
||||
father[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// 并查集里寻根的过程
|
||||
public int find(int u) {
|
||||
if (u == father[u]) {
|
||||
return u;
|
||||
} else {
|
||||
father[u] = find(father[u]);
|
||||
return father[u];
|
||||
}
|
||||
}
|
||||
|
||||
// 判断 u 和 v是否找到同一个根
|
||||
public boolean isSame(int u, int v) {
|
||||
u = find(u);
|
||||
v = find(v);
|
||||
return u == v;
|
||||
}
|
||||
|
||||
// 将v->u 这条边加入并查集
|
||||
public void join(int u, int v) {
|
||||
u = find(u); // 寻找u的根
|
||||
v = find(v); // 寻找v的根
|
||||
if (u == v) return; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
|
||||
|
||||
father[v] = u;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Python:
|
||||
|
||||
PYTHON并查集解法如下:
|
||||
|
||||
```PYTHON
|
||||
class Solution:
|
||||
def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool:
|
||||
@ -154,4 +211,3 @@ class Solution:
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
</a>
|
||||
|
||||
|
@ -110,6 +110,9 @@ if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') { // 如果节点没被
|
||||
```
|
||||
就可以通过 [200.岛屿数量](https://leetcode.cn/problems/number-of-islands/solution/by-carlsun-2-n72a/) 这道题目,大家可以去体验一下。
|
||||
|
||||
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
当然广搜还有很多细节需要注意的地方,后面我会针对广搜的题目还做针对性的讲解,因为在理论篇讲太多细节,可能会让刚学广搜的录友们越看越懵,所以细节方面针对具体题目在做讲解。
|
||||
@ -122,6 +125,37 @@ if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') { // 如果节点没被
|
||||
|
||||
相信看完本篇,大家会对广搜有一个基础性的认识,后面再来做对应的题目就会得心应手一些。
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
### Python
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
dir = [(0, 1), (1, 0), (-1, 0), (0, -1)] # 创建方向元素
|
||||
|
||||
def bfs(grid, visited, x, y):
|
||||
|
||||
queue = deque() # 初始化队列
|
||||
queue.append((x, y)) # 放入第一个元素/起点
|
||||
visited[x][y] = True # 标记为访问过的节点
|
||||
|
||||
while queue: # 遍历队列里的元素
|
||||
|
||||
curx, cury = queue.popleft() # 取出第一个元素
|
||||
|
||||
for dx, dy in dir: # 遍历四个方向
|
||||
|
||||
nextx, nexty = curx + dx, cury + dy
|
||||
|
||||
if nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]): # 越界了,直接跳过
|
||||
continue
|
||||
|
||||
if not visited[nextx][nexty]: # 如果节点没被访问过
|
||||
queue.append((nextx, nexty)) # 加入队列
|
||||
visited[nextx][nexty] = True # 标记为访问过的节点
|
||||
|
||||
```
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
@ -25,8 +25,8 @@
|
||||
|
||||
这个问题有两个陷阱:
|
||||
|
||||
* 陷阱1:栈是容器适配器,底层容器使用不同的容器,导致栈内数据在内存中是不是连续分布。
|
||||
* 陷阱2:缺省情况下,默认底层容器是deque,那么deque的在内存中的数据分布是什么样的呢? 答案是:不连续的,下文也会提到deque。
|
||||
* 陷阱1:栈是容器适配器,底层容器使用不同的容器,导致栈内数据在内存中不一定是连续分布的。
|
||||
* 陷阱2:缺省情况下,默认底层容器是deque,那么deque在内存中的数据分布是什么样的呢? 答案是:不连续的,下文也会提到deque。
|
||||
|
||||
所以这就是考察候选者基础知识扎不扎实的好问题。
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
|
||||
### 栈在系统中的应用
|
||||
|
||||
如果还记得编译原理的话,编译器在 词法分析的过程中处理括号、花括号等这个符号的逻辑,就是使用了栈这种数据结构。
|
||||
如果还记得编译原理的话,编译器在词法分析的过程中处理括号、花括号等这个符号的逻辑,就是使用了栈这种数据结构。
|
||||
|
||||
再举个例子,linux系统中,cd这个进入目录的命令我们应该再熟悉不过了。
|
||||
|
||||
@ -70,8 +70,8 @@ cd a/b/c/../../
|
||||
|
||||
先来分析一下 这里有三种不匹配的情况,
|
||||
|
||||
1. 第一种情况,字符串里左方向的括号多余了 ,所以不匹配。
|
||||
2. 第二种情况,括号没有多余,但是 括号的类型没有匹配上。
|
||||
1. 第一种情况,字符串里左方向的括号多余了,所以不匹配。
|
||||
2. 第二种情况,括号没有多余,但是括号的类型没有匹配上。
|
||||
3. 第三种情况,字符串里右方向的括号多余了,所以不匹配。
|
||||
|
||||
这里还有一些技巧,在匹配左括号的时候,右括号先入栈,就只需要比较当前元素和栈顶相不相等就可以了,比左括号先入栈代码实现要简单的多了!
|
||||
|
Reference in New Issue
Block a user