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

This commit is contained in:
programmercarl
2025-03-12 10:53:43 +08:00
7 changed files with 291 additions and 61 deletions

View File

@ -309,25 +309,25 @@ public:
0112.路径总和
```java
class solution {
public boolean haspathsum(treenode root, int targetsum) {
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false;
}
targetsum -= root.val;
targetSum -= root.val;
// 叶子结点
if (root.left == null && root.right == null) {
return targetsum == 0;
return targetSum == 0;
}
if (root.left != null) {
boolean left = haspathsum(root.left, targetsum);
if (left) { // 已经找到
boolean left = hasPathSum(root.left, targetSum);
if (left) { // 已经找到,提前返回
return true;
}
}
if (root.right != null) {
boolean right = haspathsum(root.right, targetsum);
if (right) { // 已经找到
boolean right = hasPathSum(root.right, targetSum);
if (right) { // 已经找到,提前返回
return true;
}
}
@ -336,16 +336,16 @@ class solution {
}
// lc112 简洁方法
class solution {
public boolean haspathsum(treenode root, int targetsum) {
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) return false; // 为空退出
// 叶子节点判断是否符合
if (root.left == null && root.right == null) return root.val == targetsum;
if (root.left == null && root.right == null) return root.val == targetSum;
// 求两侧分支的路径和
return haspathsum(root.left, targetsum - root.val) || haspathsum(root.right, targetsum - root.val);
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}
}
```
@ -353,22 +353,22 @@ class solution {
迭代
```java
class solution {
public boolean haspathsum(treenode root, int targetsum) {
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null) return false;
stack<treenode> stack1 = new stack<>();
stack<integer> stack2 = new stack<>();
Stack<TreeNode> stack1 = new Stack<>();
Stack<Integer> stack2 = new Stack<>();
stack1.push(root);
stack2.push(root.val);
while(!stack1.isempty()) {
while(!stack1.isEmpty()) {
int size = stack1.size();
for(int i = 0; i < size; i++) {
treenode node = stack1.pop();
TreeNode node = stack1.pop();
int sum = stack2.pop();
// 如果该节点是叶子节点了同时该节点的路径数值等于sum那么就返回true
if(node.left == null && node.right == null && sum == targetsum) {
if(node.left == null && node.right == null && sum == targetSum) {
return true;
}
// 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
@ -387,8 +387,9 @@ class solution {
}
}
```
```Java 統一迭代法
public boolean hasPathSum(TreeNode root, int targetSum) {
```Java
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
Stack<TreeNode> treeNodeStack = new Stack<>();
Stack<Integer> sumStack = new Stack<>();
@ -422,38 +423,39 @@ class solution {
}
return false;
}
}
```
0113.路径总和-ii
```java
class solution {
public List<List<Integer>> pathsum(TreeNode root, int targetsum) {
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res; // 非空判断
List<Integer> path = new LinkedList<>();
preorderdfs(root, targetsum, res, path);
preOrderDfs(root, targetSum, res, path);
return res;
}
public void preorderdfs(TreeNode root, int targetsum, List<List<Integer>> res, List<Integer> path) {
public void preOrderDfs(TreeNode root, int targetSum, List<List<Integer>> res, List<Integer> path) {
path.add(root.val);
// 遇到了叶子节点
if (root.left == null && root.right == null) {
// 找到了和为 targetsum 的路径
if (targetsum - root.val == 0) {
if (targetSum - root.val == 0) {
res.add(new ArrayList<>(path));
}
return; // 如果和不为 targetsum返回
}
if (root.left != null) {
preorderdfs(root.left, targetsum - root.val, res, path);
preOrderDfs(root.left, targetSum - root.val, res, path);
path.remove(path.size() - 1); // 回溯
}
if (root.right != null) {
preorderdfs(root.right, targetsum - root.val, res, path);
preOrderDfs(root.right, targetSum - root.val, res, path);
path.remove(path.size() - 1); // 回溯
}
}
@ -1626,3 +1628,4 @@ public class Solution {
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -261,8 +261,70 @@ public:
## 其他语言版本
### Java
三维DP数组实现
```java
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
/// 数组有三个维度
// 第一个维度:取前面的几个字符串
// 第二个维度0的数量限制背包维度 1 容量)
// 第三个维度1的数量限制背包维度 2 容量)
int[][][] dpArr = new int[strs.length][m + 1][n + 1];
/// 初始化dpArr数组
// 计算第一个字符串的零数量和1数量
int zeroNum = 0;
int oneNum = 0;
for (char c : strs[0].toCharArray()) {
if (c == '0') {
zeroNum++;
} else {
oneNum++;
}
}
// 当0数量、1数量都容得下第一个字符串时将DP数组的相应位置初始化为1因为当前的子集数量为1
for (int j = zeroNum; j <= m; j++) {
for (int k = oneNum; k <= n; k++) {
dpArr[0][j][k] = 1;
}
}
/// 依次填充加入第i个字符串之后的DP数组
for (int i = 1; i < strs.length; i++) {
zeroNum = 0;
oneNum = 0;
for (char c : strs[i].toCharArray()) {
if (c == '0') {
zeroNum++;
} else {
oneNum++;
}
}
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= n; k++) {
if (j >= zeroNum && k >= oneNum) {
// --if-- 当0数量维度和1数量维度的容量都大于等于当前字符串的0数量和1数量时才考虑是否将当前字符串放入背包
// 不放入第i个字符串子集数量仍为 dpArr[i - 1][j][k]
// 放入第i个字符串需要在0维度腾出 zeroNum 个容量1维度腾出 oneNum 个容量,然后放入当前字符串,即 dpArr[i - 1][j - zeroNum][k - oneNum] + 1)
dpArr[i][j][k] = Math.max(dpArr[i - 1][j][k], dpArr[i - 1][j - zeroNum][k - oneNum] + 1);
} else {
// --if-- 无法放入第i个字符串子集数量仍为 dpArr[i - 1][j][k]
dpArr[i][j][k] = dpArr[i - 1][j][k];
}
}
}
}
return dpArr[dpArr.length - 1][m][n];
}
}
```
二维DP数组实现
```Java
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
@ -682,3 +744,4 @@ public class Solution
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -825,30 +825,69 @@ func abs(x int) int {
### JavaScript
```javascript
/**
* 题目来源: {@link https://leetcode.cn/problems/target-sum/}
*
* 题解来源: {@link https://programmercarl.com/0494.%E7%9B%AE%E6%A0%87%E5%92%8C.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE}
*
* 时间复杂度: O(n * C), C 为数组元素总和与目标值之和的一半
*
* 空间复杂度: O(C)
*
* @param { number[] } nums
* @param { number } target
* @return { number }
*/
const findTargetSumWays = (nums, target) => {
// 原题目可转化为:
//
// 将所有元素划分为 2 个集合,
// 一个集合中包含所有要添加 "+" 号的元素, 一个集合中包含所有要添加 "-" 号的元素
//
// 设两个集合的元素和分别为 positive 和 negative, 所有元素总和为 sum, 那么有如下等式:
// positive + negative = sum (1)
// positive - negative = target (2)
// (1) 与 (2) 联立可得: positive = (sum + target) / 2,
// 所以如果能从原数组中取出若干个元素形成 1 个元素总和为 (sum + target) / 2 的集合,
// 就算得到了 1 种满足题意的组合方法
//
// 因此, 所求变为: 有多少种取法, 可使得容量为 (sum + target) / 2 的背包被装满?
const sum = nums.reduce((a, b) => a+b);
const sum = nums.reduce((a, b) => a + b);
if(Math.abs(target) > sum) {
if (Math.abs(target) > sum) {
return 0;
}
if((target + sum) % 2) {
if ((target + sum) % 2) {
return 0;
}
const halfSum = (target + sum) / 2;
let dp = new Array(halfSum+1).fill(0);
const bagWeight = (target + sum) / 2;
// 1. dp 数组的含义
// dp[j]: 装满容量为 j 的背包, 有 dp[j] 种方法
let dp = new Array(bagWeight + 1).fill(0);
// 2. 递推公式
// dp[j] = Σ(dp[j - nums[j]]), (j ∈ [0, j] 且 j >= nums[j])
// 因为 dp[j - nums[j]] 表示: 装满容量为 j - nums[j] 背包有 dp[j - nums[j]] 种方法
// 而容量为 j - nums[j] 的背包只需要再将 nums[j] 放入背包就能使得背包容量达到 j
// 因此, 让背包容量达到 j 有 Σ(dp[j - nums[j]]) 种方法
// 3. dp 数组如何初始化
// dp[0] = 1, dp[1 ~ bagWeight] = 0
dp[0] = 1;
for(let i = 0; i < nums.length; i++) {
for(let j = halfSum; j >= nums[i]; j--) {
// 4. 遍历顺序
// 先物品后背包, 物品从前往后遍历, 背包容量从后往前遍历
for (let i = 0; i < nums.length; i++) {
for (let j = bagWeight; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[halfSum];
return dp[bagWeight];
};
```

View File

@ -153,23 +153,27 @@ public:
递归
```java
class Solution {
TreeNode pre;// 记录上一个遍历的结点
TreeNode pre; // 记录上一个遍历的结点
int result = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
if(root==null)return 0;
traversal(root);
return result;
if (root == null)
return 0;
traversal(root);
return result;
}
public void traversal(TreeNode root){
if(root==null)return;
//左
public void traversal(TreeNode root) {
if (root == null)
return;
// 左
traversal(root.left);
//中
if(pre!=null){
result = Math.min(result,root.val-pre.val);
//
if (pre != null) {
result = Math.min(result, root.val - pre.val);
}
pre = root;
//右
//
traversal(root.right);
}
}
@ -182,22 +186,27 @@ class Solution {
TreeNode pre = null;
int result = Integer.MAX_VALUE;
if(root != null)
if (root != null)
stack.add(root);
while(!stack.isEmpty()){
// 中序遍历(左中右),由于栈先入后出,反序(右中左)
while (!stack.isEmpty()) {
TreeNode curr = stack.peek();
if(curr != null){
if (curr != null) {
stack.pop();
if(curr.right != null)
// 右
if (curr.right != null)
stack.add(curr.right);
// 中先用null标记
stack.add(curr);
stack.add(null);
if(curr.left != null)
// 左
if (curr.left != null)
stack.add(curr.left);
}else{
} else { // 中遇到null再处理
stack.pop();
TreeNode temp = stack.pop();
if(pre != null)
if (pre != null)
result = Math.min(result, temp.val - pre.val);
pre = temp;
}
@ -674,3 +683,4 @@ public class Solution
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -21,7 +21,7 @@
## 思路
如果想把这道题目做到极致就不要只用额外的辅助空间了 不过使用Java刷题的录友一定要使用辅助空间因为Java里的string不能修改
如果想把这道题目做到极致就不要只用额外的辅助空间了 不过使用Java和Python刷题的录友一定要使用辅助空间因为Java和Python里的string不能修改
首先扩充数组到每个数字字符替换成 "number" 之后的大小
@ -215,6 +215,46 @@ public class Main {
}
```
### Python
```python
class Solution(object):
def subsitute_numbers(self, s):
"""
:type s: str
:rtype: str
"""
count = sum(1 for char in s if char.isdigit()) # 统计数字的个数
expand_len = len(s) + (count * 5) # 计算扩充后字符串的大小, x->number 每有一个数字就要增加五个长度
res = [''] * expand_len
new_index = expand_len - 1 # 指向扩充后字符串末尾
old_index = len(s) - 1 # 指向原字符串末尾
while old_index >= 0: # 从后往前, 遇到数字替换成“number”
if s[old_index].isdigit():
res[new_index-5:new_index+1] = "number"
new_index -= 6
else:
res[new_index] = s[old_index]
new_index -= 1
old_index -= 1
return "".join(res)
if __name__ == "__main__":
solution = Solution()
while True:
try:
s = input()
result = solution.subsitute_numbers(s)
print(result)
except EOFError:
break
```
### Go
````go
package main

View File

@ -176,6 +176,81 @@ int main() {
### Java
```java
import java.util.Scanner;
public class Main {
private static int[] father;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int pointNum = scanner.nextInt();
father = new int[pointNum + 1];
init();
for (int i = 0; i < pointNum; i++) {
join(scanner.nextInt(), scanner.nextInt());
}
}
/**
* 并查集初始化
*/
private static void init() {
for (int i = 1; i < father.length; i++) {
// 让每个元素指向自己
father[i] = i;
}
}
/**
* 并查集寻根
*
* @param u
* @return
*/
private static int find(int u) {
// 判断 u 是否等于自己,如果是的话,直接返回自己
// 如果不等于自己,就寻找根,寻找的时候,反复进行路径压缩
return u == father[u] ? u : (father[u] = find(father[u]));
}
/**
* 判断 u 和 v 是否同根
*
* @param u
* @param v
* @return
*/
private static boolean isSame(int u, int v) {
return find(u) == find(v);
}
/**
* 添加 边 到并查集v 指向 u
*
* @param u
* @param v
*/
private static void join(int u, int v) {
// --if-- 如果两个点已经同根,说明他们的信息已经存储到并查集中了,直接返回即可
// 寻找u的根
int uRoot = find(u);
// 寻找v的根
int vRoot = find(v);
if (uRoot == vRoot) {
// --if-- 如果u,v的根相同说明两者已经连接了直接输出
System.out.println(u + " " + v);
return;
}
// --if-- 将信息添加到并查集
father[vRoot] = uRoot;
}
}
```
### Python
```python

View File

@ -92,10 +92,9 @@
* 递归:中序,双指针操作
* 迭代:模拟中序,逻辑相同
* [求二叉搜索树的众数](https://programmercarl.com/0501.二叉搜索树中的众数.html)
* 递归:中序,清空结果集的技巧,遍历一遍便可求众数集合
* [二叉搜索树转成累加树](https://programmercarl.com/0538.把二叉搜索树转换为累加树.html)
* [二叉搜索树转成累加树](https://programmercarl.com/0538.把二叉搜索树转换为累加树.html)
* 递归:中序,双指针操作累加
* 迭代:模拟中序,逻辑相同
@ -163,3 +162,4 @@
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>