Merge branch 'youngyangyang04:master' into master

This commit is contained in:
Leehouc
2024-10-23 20:24:48 +08:00
committed by GitHub
24 changed files with 845 additions and 48 deletions

View File

@ -256,7 +256,60 @@ public:
* 时间复杂度O(n^2)
* 空间复杂度O(1)
### Manacher 算法
Manacher 算法的关键在于高效利用回文的对称性,通过插入分隔符和维护中心、边界等信息,在线性时间内找到最长回文子串。这种方法避免了重复计算,是处理回文问题的最优解。
```c++
//Manacher 算法
class Solution {
public:
string longestPalindrome(string s) {
// 预处理字符串,在每个字符之间插入 '#'
string t = "#";
for (char c : s) {
t += c; // 添加字符
t += '#';// 添加分隔符
}
int n = t.size();// 新字符串的长度
vector<int> p(n, 0);// p[i] 表示以 t[i] 为中心的回文半径
int center = 0, right = 0;// 当前回文的中心和右边界
// 遍历预处理后的字符串
for (int i = 0; i < n; i++) {
// 如果当前索引在右边界内,利用对称性初始化 p[i]
if (i < right) {
p[i] = min(right - i, p[2 * center - i]);
}
// 尝试扩展回文
while (i - p[i] - 1 >= 0 && i + p[i] + 1 < n && t[i - p[i] - 1] == t[i + p[i] + 1]) {
p[i]++;// 增加回文半径
}
// 如果当前回文扩展超出右边界,更新中心和右边界
if (i + p[i] > right) {
center = i;// 更新中心
right = i + p[i];// 更新右边界
}
}
// 找到最大回文半径和对应的中心
int maxLen = 0, centerIndex = 0;
for (int i = 0; i < n; i++) {
if (p[i] > maxLen) {
maxLen = p[i];// 更新最大回文长度
centerIndex = i;// 更新中心索引
}
}
// 计算原字符串中回文子串的起始位置并返回
return s.substr((centerIndex - maxLen) / 2, maxLen);
}
};
```
* 时间复杂度O(n)
* 空间复杂度O(n)
## 其他语言版本
@ -682,3 +735,4 @@ public class Solution {
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -240,6 +240,42 @@ class Solution:
res = max(res, dp[i])
return res
```
动态规划
```python
class Solution:
def maxSubArray(self, nums):
if not nums:
return 0
dp = [0] * len(nums) # dp[i]表示包括i之前的最大连续子序列和
dp[0] = nums[0]
result = dp[0]
for i in range(1, len(nums)):
dp[i] = max(dp[i-1]+nums[i], nums[i]) # 状态转移公式
if dp[i] > result:
result = dp[i] # result 保存dp[i]的最大值
return result
```
动态规划优化
```python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_sum = float("-inf") # 初始化结果为负无穷大,方便比较取最大值
current_sum = 0 # 初始化当前连续和
for num in nums:
# 更新当前连续和
# 如果原本的连续和加上当前数字之后没有当前数字大,说明原本的连续和是负数,那么就直接从当前数字开始重新计算连续和
current_sum = max(current_sum+num, num)
max_sum = max(max_sum, current_sum) # 更新结果
return max_sum
```
### Go
贪心法
```go

View File

@ -143,6 +143,23 @@ class Solution:
return False
```
```python
## 基于当前最远可到达位置判断
class Solution:
def canJump(self, nums: List[int]) -> bool:
far = nums[0]
for i in range(len(nums)):
# 要考虑两个情况
# 1. i <= far - 表示 当前位置i 可以到达
# 2. i > far - 表示 当前位置i 无法到达
if i > far:
return False
far = max(far, nums[i]+i)
# 如果循环正常结束,表示最后一个位置也可以到达,否则会在中途直接退出
# 关键点在于,要想明白其实列表中的每个位置都是需要验证能否到达的
return True
```
### Go
```go

View File

@ -564,10 +564,10 @@ class Solution:
return False
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if root is None:
return False
return self.traversal(root, sum - root.val)
return self.traversal(root, targetSum - root.val)
```
(版本二) 递归 + 精简
@ -579,12 +579,12 @@ class Solution:
# self.left = left
# self.right = right
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
if not root.left and not root.right and sum == root.val:
if not root.left and not root.right and targetSum == root.val:
return True
return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)
return self.hasPathSum(root.left, targetSum - root.val) or self.hasPathSum(root.right, targetSum - root.val)
```
(版本三) 迭代
@ -596,7 +596,7 @@ class Solution:
# self.left = left
# self.right = right
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
# 此时栈里要放的是pair<节点指针,路径数值>
@ -659,13 +659,13 @@ class Solution:
return
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
self.result.clear()
self.path.clear()
if not root:
return self.result
self.path.append(root.val) # 把根节点放进路径
self.traversal(root, sum - root.val)
self.traversal(root, targetSum - root.val)
return self.result
```
@ -678,7 +678,7 @@ class Solution:
# self.left = left
# self.right = right
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
result = []
self.traversal(root, targetSum, [], result)
@ -703,7 +703,7 @@ class Solution:
# self.left = left
# self.right = right
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root:
return []
stack = [(root, [root.val])]

View File

@ -158,7 +158,7 @@ i从0开始累加rest[i]和记为curSum一旦curSum小于零说明[0, i
如果 curSum<0 说明 区间和1 + 区间和2 < 0 那么 假设从上图中的位置开始计数curSum不会小于0的话就是 区间和2>0。
区间和1 + 区间和2 < 0 同时 区间和2>0只能说明区间和1 < 0 那么就会从假设的箭头初就开始从新选择其实位置了
区间和1 + 区间和2 < 0 同时 区间和2>0只能说明区间和1 < 0 那么就会从假设的箭头初就开始从新选择起始位置了
**那么局部最优当前累加rest[i]的和curSum一旦小于0起始位置至少要是i+1因为从i之前开始一定不行。全局最优找到可以跑一圈的起始位置**

View File

@ -177,21 +177,20 @@ class Solution {
```python
class Solution:
def candy(self, ratings: List[int]) -> int:
candyVec = [1] * len(ratings)
n = len(ratings)
candies = [1] * n
# 从前向后遍历,处理右侧比左侧评分高的情况
for i in range(1, len(ratings)):
# Forward pass: handle cases where right rating is higher than left
for i in range(1, n):
if ratings[i] > ratings[i - 1]:
candyVec[i] = candyVec[i - 1] + 1
candies[i] = candies[i - 1] + 1
# 从后向前遍历,处理左侧比右侧评分高的情况
for i in range(len(ratings) - 2, -1, -1):
# Backward pass: handle cases where left rating is higher than right
for i in range(n - 2, -1, -1):
if ratings[i] > ratings[i + 1]:
candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1)
candies[i] = max(candies[i], candies[i + 1] + 1)
# 统计结果
result = sum(candyVec)
return result
return sum(candies)
```

View File

@ -108,7 +108,7 @@ public:
}
}
int result = st.top();
long long result = st.top();
st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
return result;
}

View File

@ -440,11 +440,10 @@ class Solution {
```Python
class Solution:
def reverseWords(self, s: str) -> str:
# 删除前后空白
s = s.strip()
# 反转整个字符串
s = s[::-1]
# 将字符串拆分为单词,并反转每个单词
# split()函数能够自动忽略多余的空白字符
s = ' '.join(word[::-1] for word in s.split())
return s
@ -1029,3 +1028,4 @@ public string ReverseWords(string s) {
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -459,11 +459,10 @@ class Solution:
queue = collections.deque([root])
while queue:
for i in range(len(queue)):
node = queue.popleft()
node.left, node.right = node.right, node.left
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
node = queue.popleft()
node.left, node.right = node.right, node.left
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return root
```
@ -1033,4 +1032,3 @@ public TreeNode InvertTree(TreeNode root) {
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -64,7 +64,7 @@
如果有一个字符串s在 s + s 拼接后, 不算首尾字符如果能凑成s字符串说明s 一定是重复子串组成。
如图字符串s图中数字为数组下标在 s + s 拼接后, 不算首尾字符中间凑成s字符串。
如图字符串s图中数字为数组下标在 s + s 拼接后, 不算首尾字符中间凑成s字符串。 (图中数字为数组下标)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240910115555.png)
@ -163,9 +163,7 @@ KMP算法中next数组为什么遇到字符不匹配的时候可以找到上一
如果一个字符串s是由重复子串组成那么 最长相等前后缀不包含的子串一定是字符串s的最小重复子串。
证明: 如果s 是由最小重复子串p组成
即 s = n * p
如果s 是由最小重复子串p组成,即 s = n * p
那么相同前后缀可以是这样:
@ -203,12 +201,14 @@ p2 = p1p3 = p2 即: p1 = p2 = p3
最长相等前后缀不包含的子串已经是字符串s的最小重复子串那么字符串s一定由重复子串组成这个不需要证明了。
关键是要证明最长相等前后缀不包含的子串什么时候才是字符串s的最小重复子串呢。
关键是要证明最长相等前后缀不包含的子串什么时候才是字符串s的最小重复子串呢。
情况一, 最长相等前后缀不包含的子串的长度 比 字符串s的一半的长度还大那一定不是字符串s的重复子串
情况一, 最长相等前后缀不包含的子串的长度 比 字符串s的一半的长度还大那一定不是字符串s的重复子串,如图:
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240911110236.png)
图中:前后缀不包含的子串的长度 大于 字符串s的长度的 二分之一
--------------
情况二,最长相等前后缀不包含的子串的长度 可以被 字符串s的长度整除如图
@ -230,7 +230,7 @@ p2 = p1p3 = p2 即: p1 = p2 = p3
即 s[0]s[1] 是最小重复子串
以上推导中,录友可能想,你怎么知道 s[0] 和 s[1] 就不相同呢? s[0] 为什么就不能使最小重复子串。
以上推导中,录友可能想,你怎么知道 s[0] 和 s[1] 就不相同呢? s[0] 为什么就不能最小重复子串。
如果 s[0] 和 s[1] 也相同,同时 s[0]s[1]与s[2]s[3]相同s[2]s[3] 与 s[4]s[5]相同s[4]s[5] 与 s[6]s[7] 相同,那么这个字符串就是有一个字符构成的字符串。
@ -246,7 +246,7 @@ p2 = p1p3 = p2 即: p1 = p2 = p3
或者说,自己举个例子,`aaaaaa`,这个字符串,他的最长相等前后缀是什么?
同上以上推导,最长相等前后缀不包含的子串的长度只要被 字符串s的长度整除就是一定是最小重复子串。
同上以上推导,最长相等前后缀不包含的子串的长度只要被 字符串s的长度整除最长相等前后缀不包含的子串一定是最小重复子串。
----------------
@ -267,7 +267,7 @@ p2 = p1p3 = p2 即: p1 = p2 = p3
以上推导,可以得出 s[0],s[1],s[2] 与 s[3],s[4],s[5] 相同s[3]s[4] 与 s[6]s[7]相同。
那么 最长相等前后缀不包含的子串的长度 不被 字符串s的长度整除 就不是s的重复子串
那么 最长相等前后缀不包含的子串的长度 不被 字符串s的长度整除 最长相等前后缀不包含的子串就不是s的重复子串
-----------
@ -277,7 +277,7 @@ p2 = p1p3 = p2 即: p1 = p2 = p3
在必要条件,这个是 显而易见的,都已经假设 最长相等前后缀不包含的子串 是 s的最小重复子串了那s必然是重复子串。
关键是需要证明, 字符串s的最长相等前后缀不包含的子串 什么时候才是 s最小重复子串。
**关键是需要证明, 字符串s的最长相等前后缀不包含的子串 什么时候才是 s最小重复子串**
同上我们证明了,当 最长相等前后缀不包含的子串的长度 可以被 字符串s的长度整除那么不包含的子串 就是s的最小重复子串。

View File

@ -55,7 +55,7 @@
参数必须有要遍历的树的根节点还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了所以递归函数的返回类型为void。
本题还需要类里的两个全局变量maxLen用来记录最大深度result记录最大深度最左节点的数值。
本题还需要类里的两个全局变量maxDepth用来记录最大深度result记录最大深度最左节点的数值。
代码如下:

View File

@ -168,23 +168,43 @@ for (int j = 0; j <= amount; j++) { // 遍历背包容量
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1, 0);
dp[0] = 1;
vector<uint64_t> dp(amount + 1, 0); // 防止相加数据超int
dp[0] = 1; // 只有一种方式达到0
for (int i = 0; i < coins.size(); i++) { // 遍历物品
for (int j = coins[i]; j <= amount; j++) { // 遍历背包
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
return dp[amount]; // 返回组合数
}
};
```
C++测试用例有两个数相加超过int的数据所以需要在if里加上dp[i] < INT_MAX - dp[i - num]。
* 时间复杂度: O(mn)其中 m 是amountn coins 的长度
* 空间复杂度: O(m)
为了防止相加的数据 超int 也可以这么写
```CPP
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1, 0);
dp[0] = 1; // 只有一种方式达到0
for (int i = 0; i < coins.size(); i++) { // 遍历物品
for (int j = coins[i]; j <= amount; j++) { // 遍历背包
if (dp[j] < INT_MAX - dp[j - coins[i]]) { //防止相加数据超int
dp[j] += dp[j - coins[i]];
}
}
}
return dp[amount]; // 返回组合数
}
};
```
是不是发现代码如此精简
## 总结

View File

@ -37,7 +37,7 @@
因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多。
**所以当需要固定规律一段一段去处理字符串的时候,要想想在for循环的表达式上做做文章。**
**所以当需要固定规律一段一段去处理字符串的时候要想想在for循环的表达式上做做文章。**
性能如下:
<img src='https://code-thinking.cdn.bcebos.com/pics/541_反转字符串II.png' width=600> </img></div>
@ -505,3 +505,4 @@ impl Solution {
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -100,6 +100,7 @@ public:
## 其他语言版本
### Java
排序法
```Java
class Solution {
@ -209,6 +210,43 @@ class Solution:
return new_list[::-1]
```
```python3
(双指针优化版本 三步优化
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
"""
整体思想:有序数组的绝对值最大值永远在两头,比较两头,平方大的插到新数组的最后
优 化1. 优化所有元素为非正或非负的情况
2. 头尾平方的大小比较直接将头尾相加与0进行比较即可
3. 新的平方排序数组的插入索引可以用倒序插入实现针对for循环while循环不适用
"""
# 特殊情况, 元素都非负优化1
if nums[0] >= 0:
return [num ** 2 for num in nums] # 按顺序平方即可
# 最后一个非正,全负有序的
if nums[-1] <= 0:
return [x ** 2 for x in nums[::-1]] # 倒序平方后的数组
# 一般情况, 有正有负
i = 0 # 原数组头索引
j = len(nums) - 1 # 原数组尾部索引
new_nums = [0] * len(nums) # 新建一个等长数组用于保存排序后的结果
# end_index = len(nums) - 1 # 新的排序数组(是新数组)尾插索引, 每次需要减一优化3优化了
for end_index in range(len(nums)-1, -1, -1): # (优化3倒序不用单独创建变量)
# if nums[i] ** 2 >= nums[j] ** 2:
if nums[i] + nums[j] <= 0: # (优化2)
new_nums[end_index] = nums[i] ** 2
i += 1
# end_index -= 1 (优化3)
else:
new_nums[end_index] = nums[j] ** 2
j -= 1
# end_index -= 1 (优化3)
return new_nums
```
### Go
```Go

View File

@ -164,7 +164,7 @@ class Solution {
int top = -1;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// 当 top > 0,即栈中有字符时,当前字符如果和栈中字符相等,弹出栈顶字符,同时 top--
// 当 top >= 0,即栈中有字符时,当前字符如果和栈中字符相等,弹出栈顶字符,同时 top--
if (top >= 0 && res.charAt(top) == c) {
res.deleteCharAt(top);
top--;

View File

@ -869,6 +869,65 @@ if __name__ == "__main__":
### Javascript
```js
function dijkstra(grid, start, end) {
const visited = Array.from({length: end + 1}, () => false)
const minDist = Array.from({length: end + 1}, () => Number.MAX_VALUE)
minDist[start] = 0
for (let i = 1 ; i < end + 1 ; i++) {
let cur = -1
let tempMinDist = Number.MAX_VALUE
// 1. 找尋與起始點距離最近且未被訪的節點
for (let j = 1 ; j < end + 1 ; j++) {
if (!visited[j] && minDist[j] < tempMinDist) {
cur = j
tempMinDist = minDist[j]
}
}
if (cur === -1) break;
// 2. 更新節點狀態為已拜訪
visited[cur] = true
// 3. 更新未拜訪節點與起始點的最短距離
for (let j = 1 ; j < end + 1 ; j++) {
if(!visited[j] && grid[cur][j] != Number.MAX_VALUE
&& grid[cur][j] + minDist[cur] < minDist[j]
) {
minDist[j] = grid[cur][j] + minDist[cur]
}
}
}
return minDist[end] === Number.MAX_VALUE ? -1 : minDist[end]
}
async function main() {
// 輸入
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [n, m] = (await readline()).split(" ").map(Number)
const grid = Array.from({length: n + 1},
() => Array.from({length:n + 1}, () => Number.MAX_VALUE))
for (let i = 0 ; i < m ; i++) {
const [s, e, w] = (await readline()).split(" ").map(Number)
grid[s][e] = w
}
// dijkstra
const result = dijkstra(grid, 1, n)
// 輸出
console.log(result)
}
main()
```
### TypeScript
### PhP

View File

@ -549,6 +549,62 @@ if __name__ == "__main__":
### Javascript
```js
function kruskal(v, edges) {
const father = Array.from({ length: v + 1 }, (_, i) => i)
function find(u){
if (u === father[u]) {
return u
} else {
father[u] = find(father[u])
return father[u]
}
}
function isSame(u, v) {
let s = find(u)
let t = find(v)
return s === t
}
function join(u, v) {
let s = find(u)
let t = find(v)
if (s !== t) {
father[s] = t
}
}
edges.sort((a, b) => a[2] - b[2])
let result = 0
for (const [v1, v2, w] of edges) {
if (!isSame(v1, v2)) {
result += w
join(v1 ,v2)
}
}
console.log(result)
}
async function main() {
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [v, e] = (await readline()).split(" ").map(Number)
const edges = []
for (let i = 0 ; i < e ; i++) {
edges.push((await readline()).split(" ").map(Number))
}
kruskal(v, edges)
}
main()
```
### TypeScript
### PhP

View File

@ -693,6 +693,55 @@ if __name__ == "__main__":
### Rust
### Javascript
```js
function prim(v, edges) {
const grid = Array.from({ length: v + 1 }, () => new Array(v + 1).fill(10001)); // Fixed grid initialization
const minDist = new Array(v + 1).fill(10001)
const isInTree = new Array(v + 1).fill(false)
// 建構鄰接矩陣
for(const [v1, v2, w] of edges) {
grid[v1][v2] = w
grid[v2][v1] = w
}
// prim 演算法
for (let i = 1 ; i < v ; i++) {
let cur = -1
let tempMinDist = Number.MAX_VALUE
// 1. 尋找距離生成樹最近的節點
for (let j = 1 ; j < v + 1 ; j++) {
if (!isInTree[j] && minDist[j] < tempMinDist) {
tempMinDist = minDist[j]
cur = j
}
}
// 2. 將節點放入生成樹
isInTree[cur] = true
// 3. 更新非生成樹節點與生成樹的最短距離
for (let j = 1 ; j < v + 1 ; j++) {
if (!isInTree[j] && grid[cur][j] < minDist[j]) {
minDist[j] = grid[cur][j]
}
}
}
console.log(minDist.slice(2).reduce((acc, cur) => acc + cur, 0))
}
async function main() {
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [v, e] = (await readline()).split(" ").map(Number)
const edges = []
for (let i = 0 ; i < e ; i++) {
edges.push((await readline()).split(" ").map(Number))
}
prim(v, edges)
}
main()
```
### TypeScript

View File

@ -464,6 +464,60 @@ if __name__ == "__main__":
### Javascript
```js
async function main() {
// 輸入
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [n, m] = (await readline()).split(" ").map(Number)
const grid = {}
for (let i = 0 ; i < m ; i++) {
const [src, desc, w] = (await readline()).split(" ").map(Number)
if (grid.hasOwnProperty(src)) {
grid[src].push([desc, w])
} else {
grid[src] = [[desc, w]]
}
}
const minDist = Array.from({length: n + 1}, () => Number.MAX_VALUE)
// 起始點
minDist[1] = 0
const q = [1]
const visited = Array.from({length: n + 1}, () => false)
while (q.length) {
const src = q.shift()
const neighbors = grid[src]
visited[src] = false
if (neighbors) {
for (const [desc, w] of neighbors) {
if (minDist[src] !== Number.MAX_VALUE
&& minDist[src] + w < minDist[desc]) {
minDist[desc] = minDist[src] + w
if (!visited[desc]) {
q.push(desc)
visited[desc] = true
}
}
}
}
}
// 輸出
if (minDist[n] === Number.MAX_VALUE) {
console.log('unconnected')
} else {
console.log(minDist[n])
}
}
main()
```
### TypeScript
### PhP

View File

@ -485,6 +485,45 @@ if __name__ == "__main__":
### Javascript
```js
async function main() {
// 輸入
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [n, m] = (await readline()).split(" ").map(Number)
const edges = []
for (let i = 0 ; i < m ; i++) {
edges.push((await readline()).split(" ").map(Number))
}
const minDist = Array.from({length: n + 1}, () => Number.MAX_VALUE)
// 起始點
minDist[1] = 0
for (let i = 1 ; i < n ; i++) {
let update = false
for (const [src, desc, w] of edges) {
if (minDist[src] !== Number.MAX_VALUE && minDist[src] + w < minDist[desc]) {
minDist[desc] = minDist[src] + w
update = true
}
}
if (!update) {
break;
}
}
// 輸出
if (minDist[n] === Number.MAX_VALUE) {
console.log('unconnected')
} else {
console.log(minDist[n])
}
}
main()
```
### TypeScript
### PhP

View File

@ -703,6 +703,42 @@ public class Main {
```
### Python
```python
def main():
# 輸入
n, m = map(int, input().split())
edges = list()
for _ in range(m):
edges.append(list(map(int, input().split() )))
start, end, k = map(int, input().split())
min_dist = [float('inf') for _ in range(n + 1)]
min_dist[start] = 0
# 只能經過k個城市所以從起始點到中間有(k + 1)個邊連接
# 需要鬆弛(k + 1)次
for _ in range(k + 1):
update = False
min_dist_copy = min_dist.copy()
for src, desc, w in edges:
if (min_dist_copy[src] != float('inf') and
min_dist_copy[src] + w < min_dist[desc]):
min_dist[desc] = min_dist_copy[src] + w
update = True
if not update:
break
# 輸出
if min_dist[end] == float('inf'):
print('unreachable')
else:
print(min_dist[end])
if __name__ == "__main__":
main()
```
### Go

View File

@ -499,6 +499,55 @@ main();
### Swift
### Scala
```scala
import scala.collection.mutable.Queue
import util.control.Breaks._
// Dev on LeetCode: https://leetcode.cn/problems/number-of-islands/description/
object Solution {
def numIslands(grid: Array[Array[Char]]): Int = {
val row = grid.length
val col = grid(0).length
val dir = List((-1,0), (0,-1), (1,0), (0,1)) // 四个方向
var visited = Array.fill(row)(Array.fill(col)(false))
var counter = 0
var que = Queue.empty[Tuple2[Int, Int]]
(0 until row).map{ r =>
(0 until col).map{ c =>
breakable {
if (!visited(r)(c) && grid(r)(c) == '1') {
que.enqueue((r, c))
visited(r)(c) // 只要加入队列,立刻标记
} else break // 不是岛屿不进入queue也不记录
while (!que.isEmpty) {
val cur = que.head
que.dequeue()
val x = cur(0)
val y = cur(1)
dir.map{ d =>
val nextX = x + d(0)
val nextY = y + d(1)
breakable {
// 越界就跳过
if (nextX < 0 || nextX >= row || nextY < 0 || nextY >= col) break
if (!visited(nextX)(nextY) && grid(nextX)(nextY) == '1') {
visited(nextX)(nextY) = true // 只要加入队列,立刻标记
que.enqueue((nextX, nextY))
}
}
}
}
counter = counter + 1 // 找完一个岛屿后记录一下
}
}
}
counter
}
}
```
### C#

View File

@ -412,6 +412,46 @@ const dfs = (graph, visited, x, y) => {
### Swift
### Scala
```scala
import util.control.Breaks._
object Solution {
val dir = List((-1,0), (0,-1), (1,0), (0,1)) // 四个方向
def dfs(grid: Array[Array[Char]], visited: Array[Array[Boolean]], row: Int, col: Int): Unit = {
(0 until 4).map { x =>
val nextR = row + dir(x)(0)
val nextC = col + dir(x)(1)
breakable {
if(nextR < 0 || nextR >= grid.length || nextC < 0 || nextC >= grid(0).length) break
if (!visited(nextR)(nextC) && grid(nextR)(nextC) == '1') {
visited(nextR)(nextC) = true // 经过就记录
dfs(grid, visited, nextR, nextC)
}
}
}
}
def numIslands(grid: Array[Array[Char]]): Int = {
val row = grid.length
val col = grid(0).length
var visited = Array.fill(row)(Array.fill(col)(false))
var counter = 0
(0 until row).map{ r =>
(0 until col).map{ c =>
if (!visited(r)(c) && grid(r)(c) == '1') {
visited(r)(c) = true // 经过就记录
dfs(grid, visited, r, c)
counter += 1
}
}
}
counter
}
}
```
### C#

View File

@ -223,7 +223,121 @@ public:
## 其他语言版本
### Java
DFS
```java
//这里的实现为主函数处理每个岛屿的第一块陆地 方式
//所以是主函数直接置count为1剩余的交给dfs来做。
import java.util.*;
public class Main{
static int[][] dir = {{0,-1}, {1,0}, {0,1}, {-1, 0}};//四个方向
static int count = 0;
public static void dfs(boolean[][] visited, int x, int y, int[][] grid){
for(int i = 0; i < 4; i++){
int nextX = x + dir[i][0];
int nextY = y + dir[i][1];
if(nextX < 0 || nextY < 0 || nextY >= grid[0].length || nextX >= grid.length){
continue;
}
if(!visited[nextX][nextY] && grid[nextX][nextY] == 1){
count++;
visited[nextX][nextY] = true;
dfs(visited, nextX, nextY, grid);
}
}
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[][] grid = new int[n][m];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
grid[i][j] = in.nextInt();
}
}
int result = 0;
boolean[][] visited = new boolean[n][m];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(!visited[i][j] && grid[i][j] == 1){
visited[i][j] = true;
count = 1;
dfs(visited, i, j, grid);
//dfs遍历完了一座岛屿就比较count和result保留最大的
result = Math.max(result, count);
}
}
}
System.out.println(result);
}
}
```
BFS
```java
import java.util.*;
public class Main{
static int[][] dir = {{0,-1}, {1,0}, {0,1}, {-1, 0}};//下右上左的顺序
static int count = 0;
public static void bfs(boolean[][] visited, int x, int y, int[][] grid){
Queue<pair> queue = new LinkedList<pair>();
queue.add(new pair(x,y));
count = 1; //该岛屿的第一块陆地被visit了
//对这个岛屿的所有都入队,除非上下左右都没有未访问的陆地
while(!queue.isEmpty()){
int curX = queue.peek().x;
int curY = queue.poll().y;
//对每块陆地都进行上下左右的入队和计算(遍历),自然就是按广度优先了
for(int i = 0; i < 4; i++){
int nextX = curX + dir[i][0];
int nextY = curY + dir[i][1];
if(nextX < 0 || nextY < 0 || nextX >= grid.length || nextY >= grid[0].length){
continue;
}
if(!visited[nextX][nextY] && grid[nextX][nextY] == 1){
count++;
queue.add(new pair(nextX, nextY));
visited[nextX][nextY] = true;
}
}
}
}
static class pair{
int x;
int y;
pair(int x, int y){
this.x = x;
this.y = y;
}
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[][] grid = new int[n][m];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
grid[i][j] = in.nextInt();
}
}
int result = 0;
boolean[][] visited = new boolean[n][m];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(!visited[i][j] && grid[i][j] == 1){
visited[i][j] = true;
bfs(visited, i, j, grid);
result = Math.max(result, count);
}
}
}
System.out.println(result);
}
}
```
### Python
DFS
@ -389,6 +503,144 @@ func main() {
### Rust
DFS
``` rust
use std::io;
use std::cmp;
// 定义四个方向
const DIRECTIONS: [(i32, i32); 4] = [(0, 1), (1, 0), (-1, 0), (0, -1)];
fn dfs(grid: &Vec<Vec<i32>>, visited: &mut Vec<Vec<bool>>, x: usize, y: usize, count: &mut i32) {
if visited[x][y] || grid[x][y] == 0 {
return; // 终止条件:已访问或者遇到海水
}
visited[x][y] = true; // 标记已访问
*count += 1;
for &(dx, dy) in DIRECTIONS.iter() {
let new_x = x as i32 + dx;
let new_y = y as i32 + dy;
// 检查边界条件
if new_x >= 0 && new_x < grid.len() as i32 && new_y >= 0 && new_y < grid[0].len() as i32 {
dfs(grid, visited, new_x as usize, new_y as usize, count);
}
}
}
fn main() {
let mut input = String::new();
// 读取 n 和 m
io::stdin().read_line(&mut input);
let dims: Vec<usize> = input.trim().split_whitespace().map(|s| s.parse().unwrap()).collect();
let (n, m) = (dims[0], dims[1]);
// 读取 grid
let mut grid = vec![];
for _ in 0..n {
input.clear();
io::stdin().read_line(&mut input);
let row: Vec<i32> = input.trim().split_whitespace().map(|s| s.parse().unwrap()).collect();
grid.push(row);
}
// 初始化访问记录
let mut visited = vec![vec![false; m]; n];
let mut result = 0;
// 遍历所有格子
for i in 0..n {
for j in 0..m {
if !visited[i][j] && grid[i][j] == 1 {
let mut count = 0;
dfs(&grid, &mut visited, i, j, &mut count);
result = cmp::max(result, count);
}
}
}
// 输出结果
println!("{}", result);
}
```
BFS
```rust
use std::io;
use std::collections::VecDeque;
// 定义四个方向
const DIRECTIONS: [(i32, i32); 4] = [(0, 1), (1, 0), (-1, 0), (0, -1)];
fn bfs(grid: &Vec<Vec<i32>>, visited: &mut Vec<Vec<bool>>, x: usize, y: usize) -> i32 {
let mut count = 0;
let mut queue = VecDeque::new();
queue.push_back((x, y));
visited[x][y] = true; // 标记已访问
while let Some((cur_x, cur_y)) = queue.pop_front() {
count += 1; // 增加计数
for &(dx, dy) in DIRECTIONS.iter() {
let new_x = cur_x as i32 + dx;
let new_y = cur_y as i32 + dy;
// 检查边界条件
if new_x >= 0 && new_x < grid.len() as i32 && new_y >= 0 && new_y < grid[0].len() as i32 {
let new_x_usize = new_x as usize;
let new_y_usize = new_y as usize;
// 如果未访问且是陆地,加入队列
if !visited[new_x_usize][new_y_usize] && grid[new_x_usize][new_y_usize] == 1 {
visited[new_x_usize][new_y_usize] = true; // 标记已访问
queue.push_back((new_x_usize, new_y_usize));
}
}
}
}
count
}
fn main() {
let mut input = String::new();
// 读取 n 和 m
io::stdin().read_line(&mut input).expect("Failed to read line");
let dims: Vec<usize> = input.trim().split_whitespace().map(|s| s.parse().unwrap()).collect();
let (n, m) = (dims[0], dims[1]);
// 读取 grid
let mut grid = vec![];
for _ in 0..n {
input.clear();
io::stdin().read_line(&mut input).expect("Failed to read line");
let row: Vec<i32> = input.trim().split_whitespace().map(|s| s.parse().unwrap()).collect();
grid.push(row);
}
// 初始化访问记录
let mut visited = vec![vec![false; m]; n];
let mut result = 0;
// 遍历所有格子
for i in 0..n {
for j in 0..m {
if !visited[i][j] && grid[i][j] == 1 {
let count = bfs(&grid, &mut visited, i, j);
result = result.max(count);
}
}
}
// 输出结果
println!("{}", result);
}
```
### Javascript