【Leecode 随笔】C语言版看了不后悔系列持续更新中。。。

在这里插入图片描述

🌈你好呀!我是 山顶风景独好
🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然!😊
🌸愿您在此停留的每一刻,都沐浴在轻松愉悦的氛围中。
📖这里不仅有丰富的知识和趣味横生的内容等您来探索,更是一个自由交流的平台,期待您留下独特的思考与见解。🌟
🚀让我们一起踏上这段探索与成长的旅程,携手挖掘更多可能,共同进步!💪✨

题目一:乘积最大子数组

题目描述

给定一个整数数组 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;  
}

深入剖析

  1. 时间复杂度:
    该算法的时间复杂度为 O(n),其中 n 是表达式的长度。因为我们需要遍历表达式的每个字符。
  2. 空间复杂度:
    空间复杂度为 O(n),在最坏的情况下(例如,表达式全是嵌套括号),我们需要将所有的数字和符号都存储在栈中。
  3. 算法思路:
    使用一个栈来存储数字和符号,当遇到括号时,将当前的结果和符号推入栈,以便在处理完括号内的表达式后能够恢复之前的状态。
    遍历表达式,对每个字符进行处理,根据字符的类型(数字、运算符、括号)执行相应的操作。
    处理完整个表达式后,栈中应只剩下最终的结果。

✨ 这就是今天要分享给大家的全部内容了,我们下期再见!😊
🏠 我在CSDN等你哦!我的主页😍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山顶风景独好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值