Merge branch 'jian' of github.com:JianWangUCD/leetcode-master into jian

This commit is contained in:
Jian
2025-01-17 19:38:29 +08:00
13 changed files with 391 additions and 67 deletions

View File

@ -715,26 +715,65 @@ object Solution {
### C#
```csharp
public class Solution {
public int[][] GenerateMatrix(int n) {
int[][] answer = new int[n][];
for(int i = 0; i < n; i++)
answer[i] = new int[n];
int start = 0;
int end = n - 1;
int tmp = 1;
while(tmp < n * n)
{
for(int i = start; i < end; i++) answer[start][i] = tmp++;
for(int i = start; i < end; i++) answer[i][end] = tmp++;
for(int i = end; i > start; i--) answer[end][i] = tmp++;
for(int i = end; i > start; i--) answer[i][start] = tmp++;
start++;
end--;
}
if(n % 2 == 1) answer[n / 2][n / 2] = tmp;
return answer;
public int[][] GenerateMatrix(int n)
{
// 参考Carl的代码随想录里面C++的思路
// https://www.programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html#%E6%80%9D%E8%B7%AF
int startX = 0, startY = 0; // 定义每循环一个圈的起始位置
int loop = n / 2; // 每个圈循环几次例如n为奇数3那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
int count = 1; // 用来给矩阵每个空格赋值
int mid = n / 2; // 矩阵中间的位置例如n为3 中间的位置就是(11)n为5中间位置为(2, 2)
int offset = 1;// 需要控制每一条边遍历的长度,每次循环右边界收缩一位
// 构建result二维数组
int[][] result = new int[n][];
for (int k = 0; k < n; k++)
{
result[k] = new int[n];
}
int i = 0, j = 0; // [i,j]
while (loop > 0)
{
i = startX;
j = startY;
// 四个For循环模拟转一圈
// 第一排,从左往右遍历,不取最右侧的值(左闭右开)
for (; j < n - offset; j++)
{
result[i][j] = count++;
}
// 右侧的第一列,从上往下遍历,不取最下面的值(左闭右开)
for (; i < n - offset; i++)
{
result[i][j] = count++;
}
// 最下面的第一行,从右往左遍历,不取最左侧的值(左闭右开)
for (; j > startY; j--)
{
result[i][j] = count++;
}
// 左侧第一列,从下往上遍历,不取最左侧的值(左闭右开)
for (; i > startX; i--)
{
result[i][j] = count++;
}
// 第二圈开始的时候起始位置要各自加1 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
startX++;
startY++;
// offset 控制每一圈里每一条边遍历的长度
offset++;
loop--;
}
if (n % 2 == 1)
{
// n 为奇数
result[mid][mid] = count;
}
return result;
}
```

View File

@ -130,8 +130,8 @@ public:
};
```
* 时间复杂度:$O(n)$
* 空间复杂度:$O(n)$
* 时间复杂度O(n)
* 空间复杂度O(n)
当然依然也可以,优化一下空间复杂度,代码如下:
@ -154,8 +154,8 @@ public:
};
```
* 时间复杂度:$O(n)$
* 空间复杂度:$O(1)$
* 时间复杂度O(n)
* 空间复杂度O(1)
后面将讲解的很多动规的题目其实都是当前状态依赖前两个,或者前三个状态,都可以做空间上的优化,**但我个人认为面试中能写出版本一就够了哈,清晰明了,如果面试官要求进一步优化空间的话,我们再去优化**。
@ -524,3 +524,4 @@ impl Solution {
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -1231,6 +1231,47 @@ impl Solution {
}
```
#### C#:
```C# 199.二叉树的右视图
public class Solution
{
public IList<int> RightSideView(TreeNode root)
{
var result = new List<int>();
Queue<TreeNode> queue = new();
if (root != null)
{
queue.Enqueue(root);
}
while (queue.Count > 0)
{
int count = queue.Count;
int lastValue = count - 1;
for (int i = 0; i < count; i++)
{
var currentNode = queue.Dequeue();
if (i == lastValue)
{
result.Add(currentNode.val);
}
// lastValue == i == count -1 : left 先于 right 进入Queue
if (currentNode.left != null) queue.Enqueue(currentNode.left);
if (currentNode.right != null) queue.Enqueue(currentNode.right);
//// lastValue == i == 0: right 先于 left 进入Queue
// if(currentNode.right !=null ) queue.Enqueue(currentNode.right);
// if(currentNode.left !=null ) queue.Enqueue(currentNode.left);
}
}
return result;
}
}
```
## 637.二叉树的层平均值
[力扣题目链接](https://leetcode.cn/problems/average-of-levels-in-binary-tree/)
@ -1558,6 +1599,35 @@ impl Solution {
}
```
#### C#:
```C# 二叉树的层平均值
public class Solution {
public IList<double> AverageOfLevels(TreeNode root) {
var result= new List<double>();
Queue<TreeNode> queue = new();
if(root !=null) queue.Enqueue(root);
while (queue.Count > 0)
{
int count = queue.Count;
double value=0;
for (int i = 0; i < count; i++)
{
var curentNode=queue.Dequeue();
value += curentNode.val;
if (curentNode.left!=null) queue.Enqueue(curentNode.left);
if (curentNode.right!=null) queue.Enqueue(curentNode.right);
}
result.Add(value/count);
}
return result;
}
}
```
## 429.N叉树的层序遍历
[力扣题目链接](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/)

View File

@ -40,7 +40,7 @@
本题依然是前序遍历和后序遍历都可以,前序求的是深度,后序求的是高度。
* 二叉树节点的深度指从根节点到该节点的最长简单路径边的条数或者节点数取决于深度从0开始还是从1开始
* 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数者节点数取决于高度从0开始还是从1开始
* 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数者节点数取决于高度从0开始还是从1开始
那么使用后序遍历,其实求的是根节点到叶子节点的最小距离,就是求高度的过程,不过这个最小距离 也同样是最小深度。

View File

@ -489,6 +489,67 @@ impl Solution {
}
```
### C:
```c
int str_to_int(char *str) {
// string转integer
int num = 0, tens = 1;
for (int i = strlen(str) - 1; i >= 0; i--) {
if (str[i] == '-') {
num *= -1;
break;
}
num += (str[i] - '0') * tens;
tens *= 10;
}
return num;
}
int evalRPN(char** tokens, int tokensSize) {
int *stack = (int *)malloc(tokensSize * sizeof(int));
assert(stack);
int stackTop = 0;
for (int i = 0; i < tokensSize; i++) {
char symbol = (tokens[i])[0];
if (symbol < '0' && (tokens[i])[1] == '\0') {
// pop两个数字
int num1 = stack[--stackTop];
int num2 = stack[--stackTop];
// 计算结果
int result;
if (symbol == '+') {
result = num1 + num2;
} else if (symbol == '-') {
result = num2 - num1;
} else if (symbol == '/') {
result = num2 / num1;
} else {
result = num1 * num2;
}
// push回stack
stack[stackTop++] = result;
} else {
// push数字进stack
int num = str_to_int(tokens[i]);
stack[stackTop++] = num;
}
}
int result = stack[0];
free(stack);
return result;
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -1277,6 +1277,95 @@ impl MyStack {
}
```
### C:
> C单队列
```c
typedef struct Node {
int val;
struct Node *next;
} Node_t;
// 用单向链表实现queue
typedef struct {
Node_t *head;
Node_t *foot;
int size;
} MyStack;
MyStack* myStackCreate() {
MyStack *obj = (MyStack *)malloc(sizeof(MyStack));
assert(obj);
obj->head = NULL;
obj->foot = NULL;
obj->size = 0;
return obj;
}
void myStackPush(MyStack* obj, int x) {
Node_t *temp = (Node_t *)malloc(sizeof(Node_t));
assert(temp);
temp->val = x;
temp->next = NULL;
// 添加至queue末尾
if (obj->foot) {
obj->foot->next = temp;
} else {
obj->head = temp;
}
obj->foot = temp;
obj->size++;
}
int myStackPop(MyStack* obj) {
// 获取末尾元素
int target = obj->foot->val;
if (obj->head == obj->foot) {
free(obj->foot);
obj->head = NULL;
obj->foot = NULL;
} else {
Node_t *prev = obj->head;
// 移动至queue尾部节点前一个节点
while (prev->next != obj->foot) {
prev = prev->next;
}
free(obj->foot);
obj->foot = prev;
obj->foot->next = NULL;
}
obj->size--;
return target;
}
int myStackTop(MyStack* obj) {
return obj->foot->val;
}
bool myStackEmpty(MyStack* obj) {
return obj->size == 0;
}
void myStackFree(MyStack* obj) {
Node_t *curr = obj->head;
while (curr != NULL) {
Node_t *temp = curr->next;
free(curr);
curr = temp;
}
free(obj);
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">

View File

@ -99,7 +99,7 @@ if (cur == NULL) return cur;
* 确定单层递归的逻辑
在遍历二叉搜索树的时候就是寻找区间[p->val, q->val](注意这里是左闭闭)
在遍历二叉搜索树的时候就是寻找区间[p->val, q->val](注意这里是左闭闭)
那么如果 cur->val 大于 p->val同时 cur->val 大于q->val那么就应该向左遍历说明目标区间在左子树上

View File

@ -890,6 +890,38 @@ public:
};
```
### C
```c
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
*returnSize = numsSize - k + 1;
int *res = (int*)malloc((*returnSize) * sizeof(int));
assert(res);
int *deque = (int*)malloc(numsSize * sizeof(int));
assert(deque);
int front = 0, rear = 0, idx = 0;
for (int i = 0 ; i < numsSize ; i++) {
while (front < rear && deque[front] <= i - k) {
front++;
}
while (front < rear && nums[deque[rear - 1]] <= nums[i]) {
rear--;
}
deque[rear++] = i;
if (i >= k - 1) {
res[idx++] = nums[deque[front]];
}
}
return res;
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -123,6 +123,9 @@ public:
### Java
版本一使用HashSet
```Java
// 时间复杂度O(n+m+k) 空间复杂度O(n+k)
// 其中n是数组nums1的长度m是数组nums2的长度k是交集元素的个数
import java.util.HashSet;
import java.util.Set;
@ -145,8 +148,15 @@ class Solution {
}
//方法1将结果集合转为数组
return resSet.stream().mapToInt(x -> x).toArray();
return res.stream().mapToInt(Integer::intValue).toArray();
/**
* 将 Set<Integer> 转换为 int[] 数组:
* 1. stream() : Collection 接口的方法,将集合转换为 Stream<Integer>
* 2. mapToInt(Integer::intValue) :
* - 中间操作,将 Stream<Integer> 转换为 IntStream
* - 使用方法引用 Integer::intValue将 Integer 对象拆箱为 int 基本类型
* 3. toArray() : 终端操作,将 IntStream 转换为 int[] 数组。
*/
//方法2另外申请一个数组存放setRes中的元素,最后返回数组
int[] arr = new int[resSet.size()];
@ -538,3 +548,4 @@ end
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -879,6 +879,52 @@ public int[] GetNext(string s)
}
```
### C
```c
// 前缀表不减一
int *build_next(char* s, int len) {
int *next = (int *)malloc(len * sizeof(int));
assert(next);
// 初始化前缀表
next[0] = 0;
// 构建前缀表表
int i = 1, j = 0;
while (i < len) {
if (s[i] == s[j]) {
j++;
next[i] = j;
i++;
} else if (j > 0) {
j = next[j - 1];
} else {
next[i] = 0;
i++;
}
}
return next;
}
bool repeatedSubstringPattern(char* s) {
int len = strlen(s);
int *next = build_next(s, len);
bool result = false;
// 检查最小重复片段能否被长度整除
if (next[len - 1]) {
result = len % (len - next[len - 1]) == 0;
}
free(next);
return result;
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">

View File

@ -670,18 +670,26 @@ class Solution:
# 创建二维动态规划数组,行表示选取的元素数量,列表示累加和
dp = [[0] * (target_sum + 1) for _ in range(len(nums) + 1)]
dp = [[0] * (target_sum + 1) for _ in range(len(nums))]
# 初始化状态
dp[0][0] = 1
if nums[0] <= target_sum:
dp[0][nums[0]] = 1
numZero = 0
for i in range(len(nums)):
if nums[i] == 0:
numZero += 1
dp[i][0] = int(math.pow(2, numZero))
# 动态规划过程
for i in range(1, len(nums) + 1):
for i in range(1, len(nums)):
for j in range(target_sum + 1):
dp[i][j] = dp[i - 1][j] # 不选取当前元素
if j >= nums[i - 1]:
dp[i][j] += dp[i - 1][j - nums[i - 1]] # 选取当前元素
dp[i][j] += dp[i - 1][j - nums[i]] # 选取当前元素
return dp[len(nums)][target_sum] # 返回达到目标和的方案数
return dp[len(nums)-1][target_sum] # 返回达到目标和的方案数
```

View File

@ -546,7 +546,7 @@ object Solution {
}
}
```
## C
### C
```c
int change(int amount, int* coins, int coinsSize) {
@ -593,37 +593,3 @@ public class Solution
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>
----------
回归本题,动规五步曲来分析如下:
1. 确定dp数组以及下标的含义
dp[j]凑成总金额j的货币组合数为dp[j]
2. 确定递推公式
dp[j] 就是所有的dp[j - coins[i]]考虑coins[i]的情况)相加。
所以递推公式dp[j] += dp[j - coins[i]];
**这个递推公式大家应该不陌生了我在讲解01背包题目的时候在这篇[494. 目标和](https://programmercarl.com/0494.目标和.html)中就讲解了求装满背包有几种方法公式都是dp[j] += dp[j - nums[i]];**
3. dp数组如何初始化
首先dp[0]一定要为1dp[0] = 1是 递归公式的基础。如果dp[0] = 0 的话后面所有推导出来的值都是0了。
那么 dp[0] = 1 有没有含义,其实既可以说 凑成总金额0的货币组合数为1也可以说 凑成总金额0的货币组合数为0好像都没有毛病。
但题目描述中,也没明确说 amount = 0 的情况,结果应该是多少。
这里我认为题目描述还是要说明一下因为后台测试数据是默认amount = 0 的情况组合数为1的。
下标非0的dp[j]初始化为0这样累计加dp[j - coins[i]]的时候才不会影响真正的dp[j]
dp[0]=1还说明了一种情况如果正好选了coins[i]后也就是j-coins[i] == 0的情况表示这个硬币刚好能选此时dp[0]为1表示只选coins[i]存在这样的一种选法。
----------------

View File

@ -212,13 +212,14 @@ public class Main {
int horizontalCut = 0;
for (int i = 0; i < n; i++) {
horizontalCut += horizontal[i];
result = Math.min(result, Math.abs(sum - 2 * horizontalCut));
result = Math.min(result, Math.abs((sum - horizontalCut) - horizontalCut));
// 更新result。其中horizontalCut表示前i行的和sum - horizontalCut表示剩下的和作差、取绝对值得到题目需要的“A和B各自的子区域内的土地总价值之差”。下同。
}
int verticalCut = 0;
for (int j = 0; j < m; j++) {
verticalCut += vertical[j];
result = Math.min(result, Math.abs(sum - 2 * verticalCut));
result = Math.min(result, Math.abs((sum - verticalCut) - verticalCut));
}
System.out.println(result);