文章目录
🌈你好呀!我是 山顶风景独好
🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然!😊
🌸愿您在此停留的每一刻,都沐浴在轻松愉悦的氛围中。
📖这里不仅有丰富的知识和趣味横生的内容等您来探索,更是一个自由交流的平台,期待您留下独特的思考与见解。🌟
🚀让我们一起踏上这段探索与成长的旅程,携手挖掘更多可能,共同进步!💪✨
题目一:乘积最大子数组
题目描述
给定一个整数数组 nums,找出一个非空子数组,使得该子数组的乘积最大,并返回该乘积。
示例 1:
输入: nums = [2, 3, -2, 4]
输出: 6
解释: 子数组 [2, 3] 有最大乘积 6。
示例 2:
输入: nums = [-2, 0, -1]
输出: 0
解释: 子数组 [-2, 0] 有最大乘积 0,但由于子数组不能为空,所以选择单个元素 0。
解题思路
- 这道题的关键在于处理负数和零。我们可以使用动态规划的方法,维护两个数组:一个记录到当前位置的最大乘积,另一个记录最小乘积(因为负数乘以负数可能成为最大值)。在遍历数组时,我们需要同时更新这两个值。
- 初始化两个数组 maxProd 和 minProd,分别用于存储到当前位置的最大乘积和最小乘积。
- 遍历数组,对于每个元素,更新 maxProd 和 minProd:
如果当前元素为负数,则交换 maxProd 和 minProd 的值,然后分别乘以当前元素。
如果当前元素为零,则将 maxProd 和 minProd 都设为零,但 maxProd 应设为当前元素(因为子数组不能为空)。
否则,分别用当前元素乘以 maxProd 和 minProd,然后更新它们的值。
在遍历过程中,记录全局的最大乘积。
示例代码
#include <stdio.h>
#include <limits.h>
int maxProduct(int* nums, int numsSize) {
if (numsSize == 0) return 0;
int maxProd = nums[0];
int minProd = nums[0];
int result = nums[0];
for (int i = 1; i < numsSize; i++) {
if (nums[i] < 0) {
int temp = maxProd;
maxProd = minProd;
minProd = temp;
}
maxProd = (maxProd == 0) ? nums[i] : (maxProd * nums[i]);
minProd = (minProd == 0) ? nums[i] : (minProd * nums[i]);
if (maxProd > result) {
result = maxProd;
}
}
return result;
}
int main() {
int nums1[] = {2, 3, -2, 4};
int numsSize1 = sizeof(nums1) / sizeof(nums1[0]);
printf("Maximum product of subarray: %d\n", maxProduct(nums1, numsSize1));
int nums2[] = {-2, 0, -1};
int numsSize2 = sizeof(nums2) / sizeof(nums2[0]);
printf("Maximum product of subarray: %d\n", maxProduct(nums2, numsSize2));
return 0;
}
深入剖析
此算法的时间复杂度为 O(n),因为我们只需遍历数组一次。空间复杂度为 O(1),因为我们只使用了有限的额外变量。这种方法巧妙地利用了动态规划的思想,通过维护最大和最小乘积来应对负数和零的影响。
题目二:简化路径
题目描述
以 Unix 风格给出一个文件的绝对路径,请你简化这个路径。
示例 1:
输入: “/a//bc/d//././/…”
输出: “/a/b/c”
示例 2:
输入: “/home//foo/”
输出: “/home/foo”
解题思路
这道题目要求我们对给定的路径进行简化,主要处理以下几种情况:
- 多个连续的斜杠 / 应视为一个。
- . 表示当前目录,应忽略。
- … 表示上级目录,需要回退到上一级。
- 路径开头不应有斜杠以外的字符。
我们可以使用栈来处理这个问题:
用一个栈来保存简化后的路径组件。
遍历输入路径,以斜杠 / 为分隔符拆分路径。
对每个路径组件进行处理:
空组件或 . 忽略。
… 则弹出栈顶元素(如果栈不为空)。
其他有效组件则压入栈。
最后,将栈中的组件拼接成简化后的路径。
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* simplifyPath(const char* path) {
int len = strlen(path);
char** stack = (char**)malloc(len * sizeof(char*));
int stackSize = 0;
char* token = strtok((char*)path, "/");
while (token != NULL) {
if (strcmp(token, ".") == 0 || strcmp(token, "") == 0) {
// Ignore current directory or empty string
} else if (strcmp(token, "..") == 0) {
if (stackSize > 0) {
free(stack[--stackSize]);
}
} else {
stack[stackSize++] = strdup(token);
}
token = strtok(NULL, "/");
}
// Reconstruct the simplified path
char* result = (char*)malloc((len + 1) * sizeof(char));
result[0] = '\0';
for (int i = 0; i < stackSize; i++) {
strcat(result, "/");
strcat(result, stack[i]);
free(stack[i]);
}
free(stack);
// If the result is empty, return "/"
if (result[0] == '\0') {
result[0] = '/';
result[1] = '\0';
}
return result;
}
int main() {
const char* path1 = "/a//bc/d//././/..";
printf("Simplified path: %s\n", simplifyPath(path1));
const char* path2 = "/home//foo/";
printf("Simplified path: %s\n", simplifyPath(path2));
return 0;
}
深入剖析
该算法的时间复杂度主要取决于 strtok 函数的性能和路径的长度,可以近似看作 O(n),其中 n 是路径的长度。空间复杂度也是 O(n),因为在最坏情况下,可能需要存储路径中的每个字符。使用栈结构很好地处理了路径的层级关系,使得算法简洁明了。
题目三:基本计算器
题目描述
实现一个基本的计算器来计算一个简单的字符串表达式的值。该表达式只包含非负整数、+、-、( 和 )。
示例 1:
输入: “1 + 1”
输出: 2
示例 2:
输入: “2 - 1 + 2”
输出: 3
示例 3:
输入: “(1 + (4 + 5 + 2) - 3) + (6 + 8)”
输出: 23
解题思路
这道题可以使用栈和递归的方法来解决。主要思路如下:
使用两个栈,一个用于存储当前的数字和符号,另一个用于在遇到括号时存储之前的状态。
遍历表达式,对每个字符进行处理:
如果是数字,连续读取完整的数字。
如果是 + 或 -,则将其推入符号栈,同时推入当前数字到数字栈。
如果是 (,将当前的状态(数字和符号栈的当前大小)推入一个栈用于后续恢复。
如果是 ),则计算括号内的表达式结果,并将结果作为一个数字推回数字栈。
最后,根据符号栈和数字栈计算最终结果。
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int calculate(const char* s) {
int num = 0;
int result = 0; // 用于存储最终的计算结果
int sign = 1; // 符号,1 表示正,-1 表示负
int stack[1000]; // 用于存储数字和符号的栈
int top = -1; // 栈顶指针
for (int i = 0; s[i] != '\0'; i++) {
char c = s[i];
if (isdigit(c)) {
// 如果是数字,连续读取完整的数字
num = num * 10 + (c - '0');
} else if (c == '+' || c == '-') {
// 如果是 + 或 -,则将当前数字乘以符号,并累加到结果中
result += sign * num;
num = 0; // 重置当前数字
sign = (c == '+') ? 1 : -1; // 更新符号
} else if (c == '(') {
// 如果是 (,则将当前的结果和符号推入栈,重置结果和符号
stack[++top] = result;
stack[++top] = sign;
result = 0;
sign = 1;
} else if (c == ')') {
// 如果是 ),则计算括号内的结果,并与栈顶的符号相乘
result += sign * num;
num = 0;
result *= stack[top--]; // 栈顶的符号
result += stack[top--]; // 栈顶的结果
}
}
// 处理最后一个数字
result += sign * num;
return result;
}
int main() {
const char* expression1 = "1 + 1";
printf("Result: %d\n", calculate(expression1));
const char* expression2 = "2 - 1 + 2";
printf("Result: %d\n", calculate(expression2));
const char* expression3 = "(1 + (4 + 5 + 2) - 3) + (6 + 8)";
printf("Result: %d\n", calculate(expression3));
return 0;
}
深入剖析
- 时间复杂度:
该算法的时间复杂度为 O(n),其中 n 是表达式的长度。因为我们需要遍历表达式的每个字符。- 空间复杂度:
空间复杂度为 O(n),在最坏的情况下(例如,表达式全是嵌套括号),我们需要将所有的数字和符号都存储在栈中。- 算法思路:
使用一个栈来存储数字和符号,当遇到括号时,将当前的结果和符号推入栈,以便在处理完括号内的表达式后能够恢复之前的状态。
遍历表达式,对每个字符进行处理,根据字符的类型(数字、运算符、括号)执行相应的操作。
处理完整个表达式后,栈中应只剩下最终的结果。
✨ 这就是今天要分享给大家的全部内容了,我们下期再见!😊
🏠 我在CSDN等你哦!我的主页😍