mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-07 07:35:35 +08:00
update
This commit is contained in:
@ -655,6 +655,104 @@ int main() {
|
||||
|
||||
### Java
|
||||
|
||||
```Java
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class Edge {
|
||||
int to; // 邻接顶点
|
||||
int val; // 边的权重
|
||||
|
||||
Edge(int to, int val) {
|
||||
this.to = to;
|
||||
this.val = val;
|
||||
}
|
||||
}
|
||||
|
||||
class MyComparison implements Comparator<Pair<Integer, Integer>> {
|
||||
@Override
|
||||
public int compare(Pair<Integer, Integer> lhs, Pair<Integer, Integer> rhs) {
|
||||
return Integer.compare(lhs.second, rhs.second);
|
||||
}
|
||||
}
|
||||
|
||||
class Pair<U, V> {
|
||||
public final U first;
|
||||
public final V second;
|
||||
|
||||
public Pair(U first, V second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
}
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
int n = scanner.nextInt();
|
||||
int m = scanner.nextInt();
|
||||
|
||||
List<List<Edge>> grid = new ArrayList<>(n + 1);
|
||||
for (int i = 0; i <= n; i++) {
|
||||
grid.add(new ArrayList<>());
|
||||
}
|
||||
|
||||
for (int i = 0; i < m; i++) {
|
||||
int p1 = scanner.nextInt();
|
||||
int p2 = scanner.nextInt();
|
||||
int val = scanner.nextInt();
|
||||
grid.get(p1).add(new Edge(p2, val));
|
||||
}
|
||||
|
||||
int start = 1; // 起点
|
||||
int end = n; // 终点
|
||||
|
||||
// 存储从源点到每个节点的最短距离
|
||||
int[] minDist = new int[n + 1];
|
||||
Arrays.fill(minDist, Integer.MAX_VALUE);
|
||||
|
||||
// 记录顶点是否被访问过
|
||||
boolean[] visited = new boolean[n + 1];
|
||||
|
||||
// 优先队列中存放 Pair<节点,源点到该节点的权值>
|
||||
PriorityQueue<Pair<Integer, Integer>> pq = new PriorityQueue<>(new MyComparison());
|
||||
|
||||
// 初始化队列,源点到源点的距离为0,所以初始为0
|
||||
pq.add(new Pair<>(start, 0));
|
||||
|
||||
minDist[start] = 0; // 起始点到自身的距离为0
|
||||
|
||||
while (!pq.isEmpty()) {
|
||||
// 1. 第一步,选源点到哪个节点近且该节点未被访问过(通过优先级队列来实现)
|
||||
// <节点, 源点到该节点的距离>
|
||||
Pair<Integer, Integer> cur = pq.poll();
|
||||
|
||||
if (visited[cur.first]) continue;
|
||||
|
||||
// 2. 第二步,该最近节点被标记访问过
|
||||
visited[cur.first] = true;
|
||||
|
||||
// 3. 第三步,更新非访问节点到源点的距离(即更新minDist数组)
|
||||
for (Edge edge : grid.get(cur.first)) { // 遍历 cur指向的节点,cur指向的节点为 edge
|
||||
// cur指向的节点edge.to,这条边的权值为 edge.val
|
||||
if (!visited[edge.to] && minDist[cur.first] + edge.val < minDist[edge.to]) { // 更新minDist
|
||||
minDist[edge.to] = minDist[cur.first] + edge.val;
|
||||
pq.add(new Pair<>(edge.to, minDist[edge.to]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minDist[end] == Integer.MAX_VALUE) {
|
||||
System.out.println(-1); // 不能到达终点
|
||||
} else {
|
||||
System.out.println(minDist[end]); // 到达终点最短路径
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Python
|
||||
|
||||
### Go
|
||||
|
@ -737,6 +737,73 @@ for (int v = 1; v <= n; v++) {
|
||||
|
||||
### Java
|
||||
|
||||
```Java
|
||||
import java.util.Arrays;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
int n = scanner.nextInt();
|
||||
int m = scanner.nextInt();
|
||||
|
||||
int[][] grid = new int[n + 1][n + 1];
|
||||
for (int i = 0; i <= n; i++) {
|
||||
Arrays.fill(grid[i], Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m; i++) {
|
||||
int p1 = scanner.nextInt();
|
||||
int p2 = scanner.nextInt();
|
||||
int val = scanner.nextInt();
|
||||
grid[p1][p2] = val;
|
||||
}
|
||||
|
||||
int start = 1;
|
||||
int end = n;
|
||||
|
||||
// 存储从源点到每个节点的最短距离
|
||||
int[] minDist = new int[n + 1];
|
||||
Arrays.fill(minDist, Integer.MAX_VALUE);
|
||||
|
||||
// 记录顶点是否被访问过
|
||||
boolean[] visited = new boolean[n + 1];
|
||||
|
||||
minDist[start] = 0; // 起始点到自身的距离为0
|
||||
|
||||
for (int i = 1; i <= n; i++) { // 遍历所有节点
|
||||
|
||||
int minVal = Integer.MAX_VALUE;
|
||||
int cur = 1;
|
||||
|
||||
// 1、选距离源点最近且未访问过的节点
|
||||
for (int v = 1; v <= n; ++v) {
|
||||
if (!visited[v] && minDist[v] < minVal) {
|
||||
minVal = minDist[v];
|
||||
cur = v;
|
||||
}
|
||||
}
|
||||
|
||||
visited[cur] = true; // 2、标记该节点已被访问
|
||||
|
||||
// 3、第三步,更新非访问节点到源点的距离(即更新minDist数组)
|
||||
for (int v = 1; v <= n; v++) {
|
||||
if (!visited[v] && grid[cur][v] != Integer.MAX_VALUE && minDist[cur] + grid[cur][v] < minDist[v]) {
|
||||
minDist[v] = minDist[cur] + grid[cur][v];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minDist[end] == Integer.MAX_VALUE) {
|
||||
System.out.println(-1); // 不能到达终点
|
||||
} else {
|
||||
System.out.println(minDist[end]); // 到达终点最短路径
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Python
|
||||
|
||||
### Go
|
||||
|
@ -75,6 +75,19 @@
|
||||
|
||||
## 插曲
|
||||
|
||||
-------------
|
||||
|
||||
本题和力扣 [797.所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target/description/) 是一样的,录友了解深度优先搜索之后,这道题目就是模板题,是送分题。
|
||||
|
||||
力扣是核心代码模式,把图的存储方式给大家定义好了,只需要写出深搜的核心代码就可以。
|
||||
|
||||
如果笔试的时候出一道原题 (笔试都是ACM模式,部分面试也是ACM模式),不少熟练刷力扣的录友都难住了,因为不知道图应该怎么存,也不知道自己存的图如何去遍历。
|
||||
|
||||
所以这也是为什么我要让大家练习 ACM模式
|
||||
|
||||
--------
|
||||
|
||||
|
||||
这道题目是深度优先搜索,比较好的入门题。
|
||||
|
||||
如果对深度优先搜索还不够了解,可以先看这里:[深度优先搜索的理论基础](https://programmercarl.com/图论深搜理论基础.html)
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
# 110. 字符串接龙
|
||||
|
||||
[卡码网题目链接(ACM模式)](https://kamacoder.com/problempage.php?pid=1182)
|
||||
[卡码网题目链接(ACM模式)](https://kamacoder.com/problempage.php?pid=1183)
|
||||
|
||||
题目描述
|
||||
|
||||
|
27
problems/kamacoder/0111.构造二阶行列式.md
Normal file
27
problems/kamacoder/0111.构造二阶行列式.md
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
# 111. 构造二阶行列式
|
||||
|
||||
暴力模拟就好,每个数不超过 20, 暴力枚举其实也没多大。
|
||||
|
||||
```CPP
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
for (int x = 1; x <= 20; x++) {
|
||||
for (int y = 1; y <= 20; y++) {
|
||||
for (int i = 1; i <= 20; i++) {
|
||||
for (int j = 1; j <= 20; j++) {
|
||||
if ((x * j - y * i) == n) {
|
||||
cout << x << " " << y << endl;
|
||||
cout << i << " " << j << endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cout << -1 << endl;
|
||||
}
|
||||
```
|
26
problems/kamacoder/0112.挑战boss.md
Normal file
26
problems/kamacoder/0112.挑战boss.md
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
# 112. 挑战boss
|
||||
|
||||
本题题意有点绕,注意看一下 题目描述中的【提示信息】,但是在笔试中,是不给这样的提示信息的。
|
||||
|
||||
简单模拟:
|
||||
|
||||
```CPP
|
||||
#include<iostream>
|
||||
using namespace std;
|
||||
int main() {
|
||||
int n, a, b, k = 0;
|
||||
cin >> n >> a >> b;
|
||||
string s;
|
||||
cin >> s;
|
||||
int result = 0;
|
||||
for (int i = 0; i < s.size(); i++) {
|
||||
int cur = a + k * b;
|
||||
result += cur;
|
||||
++k;
|
||||
if (s[i] == 'x') k = 0;
|
||||
}
|
||||
cout << result << endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
29
problems/kamacoder/0114.小欧的平均数.md
Normal file
29
problems/kamacoder/0114.小欧的平均数.md
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
# 114. 小欧的平均数
|
||||
|
||||
这道题非常的脑筋急转弯, 读题都要理解半天。
|
||||
|
||||
初步读题,感觉好像是求 如何最小加减,得到三个数的平均数。
|
||||
|
||||
但题意不是这样的。
|
||||
|
||||
小欧的说的三个数平衡,只是三个数里 任何两个数 相加都能被2整除, 那么 也就是说,这三个数 要么都是 奇数,要么都是偶数,才能达到小欧所说的平衡。
|
||||
|
||||
所以题目要求的,就是,三个数,最小加减1 几次 可以让三个数都变成奇数,或者都变成偶数。
|
||||
|
||||
所以最终的结果 不是1 就是0,没有其他的。
|
||||
|
||||
录友可能想,题目出的这么绕干啥? 没办法,企业的笔试题就是这样的。
|
||||
|
||||
```CPP
|
||||
#include<iostream>
|
||||
#include<algorithm>
|
||||
using namespace std;
|
||||
int main() {
|
||||
int x, y, z;
|
||||
cin >> x >> y >> z;
|
||||
int count = (x % 2 == 0) + (y % 2 == 0) + (z % 2 == 0);
|
||||
cout << min(3 - count, count);
|
||||
}
|
||||
```
|
||||
|
67
problems/kamacoder/0115.组装手机.md
Normal file
67
problems/kamacoder/0115.组装手机.md
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
# 115. 组装手机
|
||||
|
||||
这道题是比较难得哈希表题目。 把代码随想录哈希表章节理解透彻,做本题没问题。
|
||||
|
||||
思路是
|
||||
|
||||
1. 用哈希表记录 外壳售价 和 手机零件售价 出现的次数
|
||||
2. 记录总和出现的次数
|
||||
3. 遍历总和,减去 外壳售价,看 手机零件售价出现了几次
|
||||
4. 最后累加,取最大值
|
||||
|
||||
有一个需要注意的点: 数字可以重复,在计算个数的时候,如果计算重复的数字
|
||||
|
||||
例如 如果输入是
|
||||
|
||||
```
|
||||
4
|
||||
1 1 1 1
|
||||
1 1 1 1
|
||||
```
|
||||
那么输出应该是 4, 外壳售价 和 手机零件售价 是可以重复的。
|
||||
|
||||
代码如下:
|
||||
|
||||
```CPP
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
using namespace std;
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
vector<int> aVec(n, 0);
|
||||
vector<int> bVec(n, 0);
|
||||
unordered_map<int, int > aUmap;
|
||||
unordered_map<int, int > bUmap;
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> aVec[i];
|
||||
aUmap[aVec[i]]++;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> bVec[i];
|
||||
bUmap[bVec[i]]++;
|
||||
}
|
||||
unordered_set<int > uset;
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++){
|
||||
uset.insert(aVec[i] + bVec[j]);
|
||||
}
|
||||
}
|
||||
int result = 0;
|
||||
for (int sum : uset) {
|
||||
//cout << p.first << endl;
|
||||
int count = 0;
|
||||
for (pair<int, int> p : aUmap) {
|
||||
//cout << p.first - aVec[i] << endl;
|
||||
if (sum - p.first > 0 && bUmap[sum - p.first] != 0) {
|
||||
count += min(bUmap[sum - p.first], p.second);
|
||||
}
|
||||
}
|
||||
result = max(result, count);
|
||||
}
|
||||
cout << result << endl;
|
||||
}
|
||||
```
|
@ -192,7 +192,7 @@ x1, x2 为起点坐标,y1, y2 为终点坐标 ,abs 为求绝对值,sqrt
|
||||
|
||||
计算出来 F 之后,按照 F 的 大小,来选去出队列的节点。
|
||||
|
||||
可以使用 优先级队列 帮我们排好序,每次出队列,就是F最大的节点。
|
||||
可以使用 优先级队列 帮我们排好序,每次出队列,就是F最小的节点。
|
||||
|
||||
实现代码如下:(启发式函数 采用 欧拉距离计算方式)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
小美的排列询问
|
||||
# 小美的排列询问
|
||||
|
||||
注意 x 和y 不分先后
|
||||
模拟题,注意 x 和y 不分先后
|
||||
|
||||
```CPP
|
||||
|
@ -1,6 +1,11 @@
|
||||
|
||||
# 小美走公路
|
||||
|
||||
两个注意点
|
||||
在处理环形情况的时候,很多录友容易算懵了,不是多算一个数,就是少算一个数。
|
||||
|
||||
这里这样的题目,最好的方式是将 两个环展开,首尾相连,这样我们就可以通过 直线的思维去解题了
|
||||
|
||||
两个注意点:
|
||||
|
||||
1. x 可以比 y 大,题目没规定 x 和y 的大小顺序
|
||||
2. 累计相加的数可能超过int
|
@ -1,5 +1,7 @@
|
||||
|
||||
前缀和
|
||||
# 小美的蛋糕切割
|
||||
|
||||
二维前缀和,不了解前缀和的录友 可以自行查一下,是一个很容易理解的算法思路
|
||||
|
||||
```CPP
|
||||
|
||||
|
@ -36,7 +36,6 @@ void bfs(const vector<vector<char>>& grid, vector<vector<bool>>& visited, int x,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
string s;
|
||||
|
@ -1,5 +1,134 @@
|
||||
# 131. 小美的树上染色
|
||||
|
||||
贪心的思路 : https://blog.csdn.net/weixin_43739821/article/details/136299012
|
||||
本题为树形dp 稍有难度,主要在于 递推公式上。
|
||||
|
||||
dp数组的定义:
|
||||
|
||||
dp[cur][1] :当前节点染色,那么当前节点为根节点及其左右子节点中,可以染色的最大数量
|
||||
|
||||
dp[cur][0] :当前节点不染色,那么当前节点为根节点及其左右子节点中,可以染色的最大数量
|
||||
|
||||
关于 dp转移方程
|
||||
|
||||
1、 情况一:
|
||||
|
||||
如果当前节点不染色,那就去 子节点 染色 或者 不染色的最大值。
|
||||
|
||||
`dp[cur][0] += max(dp[child][0], dp[child][1]);`
|
||||
|
||||
|
||||
2、情况二:
|
||||
|
||||
那么当前节点染色的话,这种情况就不好想了。
|
||||
|
||||
首先这不是二叉树,每一个节点都有可能 会有n个子节点。
|
||||
|
||||
所以我们要分别讨论,每一个子节点的情况 对父节点的影响。
|
||||
|
||||
那么父节点 针对每种情况,就要去 最大值, 也就是 `dp[cur][1] = max(dp[cur][1], 每个自孩子的情况)`
|
||||
|
||||
如图,假如节点1 是我们要计算的父节点,节点2是我们这次要计算的子节点。
|
||||
|
||||

|
||||
|
||||
选中一个节点2 作为我们这次计算的子节点,父节点染色的话,子节点必染色。
|
||||
|
||||
接下来就是计算 父节点1和该子节点2染色的话, 以子节点2 为根的 染色节点的最大数量 。
|
||||
|
||||
是:节点2不染色 且 以节点2为根节点的最大 染色数量 + 2, + 2 是因为 节点 1 和 节点2 要颜色了,染色节点增加两个。
|
||||
|
||||
代码:`dp[child][0] + 2`
|
||||
|
||||
细心的录友会发现,那我们只计算了 红色框里面的,那么框外 最大的染色数量是多少呢?
|
||||
|
||||

|
||||
|
||||
|
||||
先看 作为子节点的节点2 为根节点的最大染色数量是多少? 取一个最值,即 节点2染色 或者 不染色取最大值。
|
||||
|
||||
代码:`max(dp[child][0], dp[child][1])`
|
||||
|
||||
那么红框以外的 染色最大节点数量 就是 `dp[cur][0] - max(dp[child][0], dp[child][1])`
|
||||
|
||||
(cur是节点1,child是节点2)
|
||||
|
||||
红框以外的染色最大数量 + 父节点1和该子节点2染色的话 以子节点2 为根的 染色节点的最大数量 就是 节点1 染色的最大节点数量。
|
||||
|
||||
代码:
|
||||
|
||||
`dp[cur][1] = max(dp[cur][1], dp[cur][0] - max(dp[child][0], dp[child][1]) + dp[child][0] + 2);`
|
||||
|
||||
整体代码如下:
|
||||
|
||||
```CPP
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int maxN = 10005;
|
||||
vector<vector<int>> dp (maxN, vector<int>(2, 0));
|
||||
vector<list<int>> grid(maxN); // 邻接表
|
||||
vector<long> value(maxN); // 存储每个节点的权值
|
||||
|
||||
|
||||
// 在树上进行动态规划的函数
|
||||
void dpOnTheTree(int cur) {
|
||||
|
||||
for (int child : grid[cur]) {
|
||||
// 后序遍历,从下向上计算
|
||||
dpOnTheTree(child);
|
||||
// 情况一
|
||||
dp[cur][0] += max(dp[child][0], dp[child][1]);
|
||||
|
||||
}
|
||||
|
||||
// 计算dp[1] - 当前节点染色
|
||||
for (int child : grid[cur]) {
|
||||
long mul = value[cur] * value[child]; // 当前节点和相邻节点权值的乘积
|
||||
long sqrtNum = (long) sqrt(mul);
|
||||
|
||||
if (sqrtNum * sqrtNum == mul) { // 如果乘积是完全平方数
|
||||
// 情况二
|
||||
// dp[cur][0] 表示所有子节点 染色或者不染色的 最大染色数量
|
||||
// max(dp[child][0], dp[child][1]) 需要染色节点的孩子节点的最大染色数量
|
||||
// dp[cur][0] - max(dp[child][0], dp[child][1]) 除了要染色的节点及其子节点,其他孩子的最大染色数量
|
||||
// 最后 + dp[child][0] + 2 , 就是本节点染色的最大染色节点数量
|
||||
dp[cur][1] = max(dp[cur][1], dp[cur][0] - max(dp[child][0], dp[child][1]) + dp[child][0] + 2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
int n;
|
||||
cin >> n; // 输入节点数量
|
||||
|
||||
// 读取节点权值
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
cin >> value[i];
|
||||
}
|
||||
|
||||
// 构建树的邻接表
|
||||
for (int i = 1; i < n; ++i) {
|
||||
int x, y;
|
||||
cin >> x >> y;
|
||||
grid[x].push_back(y);
|
||||
}
|
||||
|
||||
// 从根节点(节点1)开始进行动态规划
|
||||
dpOnTheTree(1);
|
||||
|
||||
// 输出最大染色节点数量
|
||||
cout << max(dp[1][0], dp[1][1]) << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
dp思路:https://www.cnblogs.com/ganyq/p/18111114
|
||||
|
47
problems/kamacoder/夹吃旗.md
Normal file
47
problems/kamacoder/夹吃旗.md
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int t = 0;
|
||||
|
||||
cin >> t;
|
||||
|
||||
while(t--) {
|
||||
vector<string> grid(3, "");
|
||||
int a = 0;
|
||||
int b = 0;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
cin >> grid[i];
|
||||
if(grid[i] == "o*o") {
|
||||
a++;
|
||||
} else if(grid[i] == "*o*") {
|
||||
b++;
|
||||
}
|
||||
}
|
||||
// 判断列
|
||||
for(int i = 0; i < 3; i++) {
|
||||
string line(1, grid[0][i]);
|
||||
line += grid[1][i];
|
||||
line += grid[2][i];
|
||||
|
||||
if(line == "o*o") {
|
||||
a++;
|
||||
} else if(line == "*o*") {
|
||||
b++;
|
||||
}
|
||||
}
|
||||
if((a && b) || (!a && !b)) {
|
||||
cout << "draw" << endl;
|
||||
}
|
||||
if(a && !b) {
|
||||
cout << "yukan" << endl;
|
||||
}
|
||||
if(!a && b) {
|
||||
cout << "kou" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user