文章目录
🌈你好呀!我是 山顶风景独好
🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然!😊
🌸愿您在此停留的每一刻,都沐浴在轻松愉悦的氛围中。
📖这里不仅有丰富的知识和趣味横生的内容等您来探索,更是一个自由交流的平台,期待您留下独特的思考与见解。🌟
🚀让我们一起踏上这段探索与成长的旅程,携手挖掘更多可能,共同进步!💪✨
题目一:最小栈
题目描述:
设计一个支持 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)时间内获取最小值。同时,需要注意内存管理,特别是在栈扩容时,要确保辅助栈和主栈同步扩容。
题目二:相交链表
题目描述:
给定两个链表,编写一个程序找到两个链表的交点。
示例输入与输出:
- 输入:A = 4->1, B = 5->6->1, C = 8->4->5(A和B相交于节点1)
输出:1->…- 输入: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等你哦!我的主页😍