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

在这里插入图片描述

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

题目一:最小栈

题目描述:

设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) – 将元素 x 推入栈中。
pop() – 删除栈顶的元素。
top() – 获取栈顶元素。
getMin() – 检索栈中的最小元素。

示例输入与输出:

MinStack* minStack = minStackCreate(); minStackPush(minStack, -2); minStackPush(minStack, 0); minStackPush(minStack, -3); // 返回 -3. minStackGetMin(minStack); minStackPop(minStack); // 返回 0. minStackTop(minStack); // 返回 -2. minStackGetMin(minStack);

MinStack* minStack = minStackCreate();  
minStackPush(minStack, 3);  
minStackPush(minStack, 5);  
// 返回 3.  
minStackGetMin(minStack);  
minStackPop(minStack);  
// 返回 5.  
minStackTop(minStack);  
// 返回 5.  
minStackGetMin(minStack);

解题思路:

为了实现常数时间内检索到最小元素,我们需要维护一个辅助栈来记录当前栈中的最小值。每次push操作时,我们将新元素压入主栈,同时更新最小值栈;如果新元素小于或等于当前最小值,则将其压入最小值栈。pop操作时,如果弹出的元素等于最小值栈的栈顶,则同时弹出最小值栈的栈顶。这样,我们就可以保证getMin操作始终能在常数时间内完成。

示例代码:

#include <stdlib.h>  
#include <stdio.h>  
#include <limits.h>  
  
typedef struct MinStack {  
    int* stack;  
    int* minStack;  
    int top;  
    int minTop;  
    int capacity;  
} MinStack;  
  
/** initialize your data structure here. */  
MinStack* minStackCreate() {  
    MinStack* stack = (MinStack*)malloc(sizeof(MinStack));  
    stack->capacity = 100;  
    stack->stack = (int*)malloc(stack->capacity * sizeof(int));  
    stack->minStack = (int*)malloc(stack->capacity * sizeof(int));  
    stack->top = -1;  
    stack->minTop = -1;  
    return stack;  
}  
  
void minStackPush(MinStack* obj, int x) {  
    if (obj->top == obj->capacity - 1) {  
        obj->capacity *= 2;  
        obj->stack = (int*)realloc(obj->stack, obj->capacity * sizeof(int));  
        obj->minStack = (int*)realloc(obj->minStack, obj->capacity * sizeof(int));  
    }  
    obj->stack[++(obj->top)] = x;  
    if (obj->minTop == -1 || x <= obj->minStack[obj->minTop]) {  
        obj->minStack[++(obj->minTop)] = x;  
    }  
}  
  
void minStackPop(MinStack* obj) {  
    if (obj->top == -1) return;  
    if (obj->stack[obj->top] == obj->minStack[obj->minTop]) {  
        obj->minTop--;  
    }  
    obj->top--;  
}  
  
int minStackTop(MinStack* obj) {  
    return obj->stack[obj->top];  
}  
  
int minStackGetMin(MinStack* obj) {  
    return obj->minStack[obj->minTop];  
}  
  
void minStackFree(MinStack* obj) {  
    free(obj->stack);  
    free(obj->minStack);  
    free(obj);  
}  
  
// 测试代码  
int main() {  
    MinStack* minStack = minStackCreate();  
    minStackPush(minStack, -2);  
    minStackPush(minStack, 0);  
    minStackPush(minStack, -3);  
    printf("Min: %d\n", minStackGetMin(minStack)); // 输出 -3  
    minStackPop(minStack);  
    printf("Top: %d\n", minStackTop(minStack)); // 输出 0  
    printf("Min: %d\n", minStackGetMin(minStack)); // 输出 -2  
    minStackFree(minStack);  
    return 0;  
}

深入剖析:

该算法的关键在于利用辅助栈来维护当前的最小值,这样我们在任何时刻都可以在O(1)时间内获取最小值。同时,需要注意内存管理,特别是在栈扩容时,要确保辅助栈和主栈同步扩容。

题目二:相交链表

题目描述:

给定两个链表,编写一个程序找到两个链表的交点。

示例输入与输出:

  1. 输入:A = 4->1, B = 5->6->1, C = 8->4->5(A和B相交于节点1)
    输出:1->…
  2. 输入:A = 1->2->3, B = 4->5->6(A和B不相交)
    输出:null

解题思路:

我们可以使用双指针法来解决这个问题。假设链表A的长度为m,链表B的长度为n。当链表A和链表B不相交时,遍历完A和B之后,总共走了m+n步。如果两个链表相交,假设交点距离A链表头部为a,距离B链表头部为b,那么A链表走到交点的步数为a,B链表走到交点的步数为b。当链表A走完m步后,我们可以让指针开始遍历链表B;同时,让遍历完链表B的指针开始遍历链表A。如果两个链表相交,那么这两个指针会在交点相遇,此时两者都走了a+b+m-a=b+n-b=m+n步。

示例代码:

#include <stdlib.h>  
#include <stdio.h>  
  
// 定义链表节点  
struct ListNode {  
    int val;  
    struct ListNode *next;  
};  
  
// 创建新节点  
struct ListNode* createNode(int val) {  
    struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));  
    newNode->val = val;  
    newNode->next = NULL;  
    return newNode;  
}  
  
// 找到相交节点  
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {  
    struct ListNode *pA = headA, *pB = headB;  
    while (pA != pB) {  
        pA = pA ? pA->next : headB;  
        pB = pB ? pB->next : headA;  
    }  
    return pA;  
}  
  
// 测试代码  
int main() {  
    // 创建链表A: 4->1  
    struct ListNode* A = createNode(4);  
    A->next = createNode(1);  
      
    // 创建链表B: 5->6->1  
    struct ListNode* B = createNode(5);  
    B->next = createNode(6);  
    B->next->next = A->next; // 让B与A在节点1相交  
      
    // 找到相交节点  
    struct ListNode* intersection = getIntersectionNode(A, B);  
    if (intersection) {  
        printf("Intersection at: %d\n", intersection->val); // 输出 1  
    } else {  
        printf("No intersection found.\n");  
    }  
      
    // 释放内存  
    free(A->next);  
    free(A);  
    free(B->next->next);  
    free(B->next);  
    free(B);  
      
    return 0;  
}

深入剖析:

该算法利用双指针和链表的性质,巧妙地避免了额外的空间开销,同时时间复杂度为O(n+m),非常高效。需要注意的是,在实际应用中,应确保链表的节点没有被重复释放,以避免内存错误。

题目三:岛屿的周长

题目描述:

给定一个由0和1组成的二维网格,其中1表示陆地,0表示水域。请你计算这个网格中所有岛屿的周长。岛屿被水域包围,并且由垂直或者水平相邻的1组成。你可以假定网格的四个边都被水域包围。

示例输入与输出:

输入:
[[0,1,0,0],
[1,1,1,0],
[0,1,0,0],
[1,1,0,0]]
输出:
16
解释:
这个示例中,有两座岛屿,它们的周长分别是8和8,相加得到16。

解题思路:

遍历整个网格,对于每一个陆地(值为1)的格子,我们检查它的上方、下方、左边和右边是否为水域(值为0)或者是网格的边界。每发现一个相邻的水域或边界,就将周长加1。需要注意的是,对于每个格子,我们只计算它上方和左边的相邻情况,以避免重复计算。

示例代码:

#include <stdio.h>  
#include <stdlib.h>  
  
int islandPerimeter(int** grid, int gridSize, int* gridColSize) {  
    int perimeter = 0;  
    for (int i = 0; i < gridSize; i++) {  
        for (int j = 0; j < gridColSize[i]; j++) {  
            if (grid[i][j] == 1) {  
                perimeter += 4; // 初始假设当前格子的四个边都是周长的一部分  
                if (i > 0 && grid[i - 1][j] == 1) {  
                    perimeter -= 2; // 如果上方有陆地,减去2  
                }  
                if (j > 0 && grid[i][j - 1] == 1) {  
                    perimeter -= 2; // 如果左方有陆地,减去2  
                }  
            }  
        }  
    }  
    return perimeter;  
}  
  
// 测试代码  
int main() {  
    int gridRowSize = 4;  
    int gridColSize[] = {4, 4, 4, 4}; // 每行的列数  
    int** grid = (int**)malloc(gridRowSize * sizeof(int*));  
  
    grid[0] = (int*)malloc(4 * sizeof(int));  
    grid[0][0] = 0; grid[0][1] = 1; grid[0][2] = 0; grid[0][3] = 0;  
    grid[1] = (int*)malloc(4 * sizeof(int));  
    grid[1][0] = 1; grid[1][1] = 1; grid[1][2] = 1; grid[1][3] = 0;  
    grid[2] = (int*)malloc(4 * sizeof(int));  
    grid[2][0] = 0; grid[2][1] = 1; grid[2][2] = 0; grid[2][3] = 0;  
    grid[3] = (int*)malloc(4 * sizeof(int));  
    grid[3][0] = 1; grid[3][1] = 1; grid[3][2] = 0; grid[3][3] = 0;  
  
    int perimeter = islandPerimeter(grid, gridRowSize, gridColSize);  
    printf("Perimeter: %d\n", perimeter); // 输出 16  
  
    // 释放内存  
    for (int i = 0; i < gridRowSize; i++) {  
        free(grid[i]);  
    }  
    free(grid);  
  
    return 0;  
}

深入剖析:

该算法通过遍历每个格子,检查其相邻格子的状态来计算周长,时间复杂度为O(n*m),其中n为行数,m为列数。这种方法简单直接,适用于大多数情况。需要注意的是,在实际应用中,应确保动态分配的内存得到正确释放,以避免内存泄漏。


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

山顶风景独好

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

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

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

打赏作者

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

抵扣说明:

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

余额充值