diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md
index a2f664a4..6a13a21c 100644
--- a/problems/0070.爬楼梯.md
+++ b/problems/0070.爬楼梯.md
@@ -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 {
+
diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md
index cd7096ac..708e0532 100644
--- a/problems/0111.二叉树的最小深度.md
+++ b/problems/0111.二叉树的最小深度.md
@@ -40,7 +40,7 @@
本题依然是前序遍历和后序遍历都可以,前序求的是深度,后序求的是高度。
* 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
-* 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数后者节点数(取决于高度从0开始还是从1开始)
+* 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)
那么使用后序遍历,其实求的是根节点到叶子节点的最小距离,就是求高度的过程,不过这个最小距离 也同样是最小深度。
diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md
index 5fb28c29..bc73f6da 100644
--- a/problems/0150.逆波兰表达式求值.md
+++ b/problems/0150.逆波兰表达式求值.md
@@ -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;
+}
+```
+
diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md
index caa24d8d..9bb3494d 100644
--- a/problems/0239.滑动窗口最大值.md
+++ b/problems/0239.滑动窗口最大值.md
@@ -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;
+}
+
+```
+
diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md
index 6ddf774d..4a1fc6ab 100644
--- a/problems/0494.目标和.md
+++ b/problems/0494.目标和.md
@@ -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] # 返回达到目标和的方案数
```
diff --git a/problems/0518.零钱兑换II.md b/problems/0518.零钱兑换II.md
index 833d5ed6..835df852 100644
--- a/problems/0518.零钱兑换II.md
+++ b/problems/0518.零钱兑换II.md
@@ -546,7 +546,7 @@ object Solution {
}
}
```
-## C
+### C
```c
int change(int amount, int* coins, int coinsSize) {
@@ -593,37 +593,3 @@ public class Solution
diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md
index f0fe3a3c..73d9db1b 100644
--- a/problems/0225.用队列实现栈.md
+++ b/problems/0225.用队列实现栈.md
@@ -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);
+}
+
+```
+
diff --git a/problems/0459.重复的子字符串.md b/problems/0459.重复的子字符串.md
index 2be8922b..de0e6e4d 100644
--- a/problems/0459.重复的子字符串.md
+++ b/problems/0459.重复的子字符串.md
@@ -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;
+}
+
+```
+
-
-----------
-
-
-
-回归本题,动规五步曲来分析如下:
-
-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]一定要为1,dp[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]存在这样的一种选法。
-
-----------------