代码随想录算法训练营第十天|Day10栈与队列

232.用栈实现队列

题目链接/文章讲解/视频讲解:https://programmercarl.com/0232.%E7%94%A8%E6%A0%88%E5%AE%9E%E7%8E%B0%E9%98%9F%E5%88%97.html

思路

这是一道模拟题,不涉及到具体算法,使用栈来模拟队列的行为,如果仅仅用一个栈,是一定不行的,所以需要两个栈一个输入栈,一个输出栈。

#define MAX_SIZE 1000   
typedef struct {  
    int top;  
    int data[MAX_SIZE];  
} Stack;  
void initStack(Stack *stack) {  
    stack->top = -1;  
}   
bool isEmpty(Stack *stack) {  
    return stack->top == -1;  
}   
void push(Stack *stack, int value) {  
    if (stack->top < MAX_SIZE - 1) {  
        stack->data[++stack->top] = value;  
    } else {  
        printf("Stack overflow\n");  
    }  
}   
int pop(Stack *stack) {  
    if (!isEmpty(stack)) {  
        return stack->data[stack->top--];  
    } else {  
        printf("Stack underflow\n");  
        return -1;  
    }  
}  
int peek(Stack *stack) {  
    if (!isEmpty(stack)) {  
        return stack->data[stack->top];  
    } else {  
        printf("Stack is empty\n");  
        return -1;  
    }  
}  
  
typedef struct {  
    Stack inputStack;  
    Stack outputStack;  
} MyQueue;  
MyQueue* myQueueCreate() {  
    MyQueue *obj = (MyQueue*)malloc(sizeof(MyQueue));  
    initStack(&obj->inputStack);  
    initStack(&obj->outputStack);  
    return obj;  
}  
void myQueuePush(MyQueue* obj, int x) {  
    push(&obj->inputStack, x);  
}  
void moveElements(Stack *inputStack, Stack *outputStack) {  
    while (!isEmpty(inputStack)) {  
        push(outputStack, pop(inputStack));  
    }  
}    
int myQueuePop(MyQueue* obj) {  
    if (isEmpty(&obj->outputStack)) {  
        moveElements(&obj->inputStack, &obj->outputStack);  
    }  
    return pop(&obj->outputStack);  
}  
int myQueuePeek(MyQueue* obj) {  
    if (isEmpty(&obj->outputStack)) {  
        moveElements(&obj->inputStack, &obj->outputStack);  
    }  
    return peek(&obj->outputStack);  
}   
bool myQueueEmpty(MyQueue* obj) {  
    return isEmpty(&obj->inputStack) && isEmpty(&obj->outputStack);  
}  
void myQueueFree(MyQueue* obj) {  
    free(obj);  
}  

学习反思

栈和队列的原理:队列是先进先出,栈是先进后出。

225. 用队列实现栈

题目链接/文章讲解/视频讲解:https://programmercarl.com/0225.%E7%94%A8%E9%98%9F%E5%88%97%E5%AE%9E%E7%8E%B0%E6%A0%88.html

思路

typedef struct {
    int* data;
    int front;
    int back;
    int size;
    int capacity;
} Queue;
Queue* createQueue(int capacity) {
    Queue* queue = (Queue*)malloc(sizeof(Queue));
    queue->data = (int*)malloc(sizeof(int) * capacity);
    queue->front = 0;
    queue->back = 0;
    queue->size = 0;
    queue->capacity = capacity;
    return queue;
}
void enqueue(Queue* queue, int value) {
    queue->data[queue->back] = value;
    queue->back = (queue->back + 1) % queue->capacity;
    queue->size++;
}
int dequeue(Queue* queue) {
    int value = queue->data[queue->front];
    queue->front = (queue->front + 1) % queue->capacity;
    queue->size--;
    return value;
}
int peek(Queue* queue) {
    return queue->data[queue->front];
}
bool isEmpty(Queue* queue) {
    return queue->size == 0;
}
void freeQueue(Queue* queue) {
    free(queue->data);
    free(queue);
}
typedef struct {
    Queue* queue1;
    Queue* queue2;
} MyStack;
MyStack* myStackCreate() {
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    obj->queue1 = createQueue(100); // 初始化队列,容量设定为 100
    obj->queue2 = createQueue(100);
    return obj;
}
void myStackPush(MyStack* obj, int x) {
    enqueue(obj->queue2, x);
    while (!isEmpty(obj->queue1)) {
        enqueue(obj->queue2, dequeue(obj->queue1));
    }
    Queue* temp = obj->queue1;
    obj->queue1 = obj->queue2;
    obj->queue2 = temp;
}
int myStackPop(MyStack* obj) {
    return dequeue(obj->queue1);
}
int myStackTop(MyStack* obj) {
    return peek(obj->queue1);
}
bool myStackEmpty(MyStack* obj) {
    return isEmpty(obj->queue1);
}
void myStackFree(MyStack* obj) {
    freeQueue(obj->queue1);
    freeQueue(obj->queue2);
    free(obj);
}

学习反思

队列模拟栈,其实一个队列就够了,那么我们先说一说两个队列来实现栈的思路。队列是先进先出的规则,把一个队列中的数据导入另一个队列中,数据的顺序并没有变,并没有变成先进后出的顺序。所以用栈实现队列, 和用队列实现栈的思路还是不一样的,这取决于这两个数据结构的性质。但是依然还是要用两个队列来模拟栈,只不过没有输入和输出的关系,而是另一个队列完全用来备份的!用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1。

20. 有效的括号

题目链接/文章讲解/视频讲解:https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html

思路

int notMatch(char par, char* stack, int stackTop) {
    switch(par) {
        case ']':
            return stack[stackTop - 1] != '[';
        case ')':
            return stack[stackTop - 1] != '(';
        case '}':
            return stack[stackTop - 1] != '{';
    }
    return 0;
}
bool isValid(char * s){
    int strLen = strlen(s);
    char stack[5000];
    int stackTop = 0;
    int i;
    for(i = 0; i < strLen; i++) {
        char tempChar = s[i];
        if(tempChar == '(' || tempChar == '[' || tempChar == '{')
            stack[stackTop++] = tempChar;
        else if(stackTop == 0 || notMatch(tempChar, stack, stackTop))
            return 0;
        else
            stackTop--;
    }
    return !stackTop;
}

学习反思

由于栈结构的特殊性,非常适合做对称匹配类的题目。

首先要弄清楚,字符串里的括号不匹配有几种情况。

一些同学,在面试中看到这种题目上来就开始写代码,然后就越写越乱。

建议在写代码之前要分析好有哪几种不匹配的情况,如果不在动手之前分析好,写出的代码也会有很多问题。

先来分析一下 这里有三种不匹配的情况,

  1. 第一种情况,字符串里左方向的括号多余了 ,所以不匹配。

  2. 第二种情况,括号没有多余,但是 括号的类型没有匹配上。 

  3. 第三种情况,字符串里右方向的括号多余了,所以不匹配

我们的代码只要覆盖了这三种不匹配的情况,就不会出问题,可以看出 动手之前分析好题目的重要性。

第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false

第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false

第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false

1047. 删除字符串中的所有相邻重复项

题目链接/文章讲解/视频讲解:https://programmercarl.com/1047.%E5%88%A0%E9%99%A4%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E7%9B%B8%E9%82%BB%E9%87%8D%E5%A4%8D%E9%A1%B9.html

思路

char* removeDuplicates(char* s) {
    int len = strlen(s);
    char* stack = (char*)malloc((len + 1) * sizeof(char)); 
    int stackSize = 0;
    for (int i = 0; i < len; i++) {
        if (stackSize > 0 && stack[stackSize - 1] == s[i]) {
            stackSize--;
        } else {
            stack[stackSize] = s[i];
            stackSize++;
        }
    }
    stack[stackSize] = '\0'; 
    char* result = (char*)malloc((stackSize + 1) * sizeof(char)); 
    strcpy(result, stack); 
    free(stack);
    return result; 
}

学习反思

这个函数通过动态内存分配来创建一个临时的栈,并在处理完字符串后,将其内容复制到一个新的字符串中,然后返回这个新字符串。

总结

了解了队列和栈,加油!!!

 

第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二天的算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值