LeetCode 栈和队列OJ题目分享

有效的括号(括号匹配)

链接: link
题目描述:
在这里插入图片描述
题目思路:

1、如果是左括号“( { [ ”就入栈

2、如果是右括号“) } ] ”,就取出栈顶元素与该右括号进行匹配
如果不匹配,就直接return false
如果匹配,s++,指针继续向下走,寻找下一个括号,进行上述操作

注意:
1、如果只有左括号,则栈不为空,则要return false
2、如果只有右括号,栈为空,不能取栈顶元素进行匹配
3、内存泄漏问题,每次返回一个bool值之前都要销毁栈,以免发生内存泄漏
代码实现:

typedef char STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;//最开始不malloc空间
	//pst->top = -1;//指向栈顶元素
	pst->top = 0;//指向栈顶元素的下一个位置,表示已经有元素
	pst->capacity = 0;
}
void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}
void STPush(ST* pst, STDataType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];//栈顶元素
}
bool STEmpty(ST* pst)
{
	return pst->top == 0;
}
int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

bool isValid(char * s)
{
    ST st;
    STInit(&st);
    while(*s)
    {
         //1、左括号入栈
        if(*s=='('
        || *s=='{'
        || *s=='[')
        {
            STPush(&st,*s);
        }
        //2、右括号出栈匹配
        else
        {
            //不匹配情况

            //如果栈空,只有右括号,则不匹配,直接返回false
            if(STEmpty(&st))
            {
                return false;
            }
            char top = STTop(&st);
            STPop(&st);
            if((*s==']'&&top!='[')
            || (*s=='}'&&top!='{')
            ||(*s==')'&&top!='('))
            {
                return false;
            }
            //匹配
        }
        s++;//向后遍历字符串寻找括号
    }
    bool ret = STEmpty(&st);//如果栈空返回true,否则返回false
    STDestroy(&st);
    return ret;
}

用栈实现队列

链接: link
题目描述:
在这里插入图片描述
在这里插入图片描述
题目思路:

两个栈实现队列,首先明确:
栈后进先出
队列先进先出

![在这里插入图片描述](https://img-blog.csdnimg.cn/a031ca50ab964ca6bd8b008f47c65dbf.png方法:
方法:
在这里插入图片描述

此处方法就是先倒数据,将栈1的元素4 3 2全部导入栈2中,最后删除1,如下图

在这里插入图片描述

在这个过程中,将栈1的全部元素导入栈2后,我们可以发现栈2出栈的顺序就是队列出队的顺序,于是可以将两个栈做如下更改:

在这里插入图片描述
分析:

1、队列的结构

typedef struct 
{
    ST pushst;
    ST popst;
} MyQueue;
MyQueue* myQueueCreate() 
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    if(obj==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}

2、入队操作
在这里插入图片描述

此处入队操作就是入栈操作,将元素入到pushst栈当中

void myQueuePush(MyQueue* obj, int x) 
{
    STPush(&obj->pushst,x);
}

3、返回队列开头元素在这里插入图片描述

首先判断popst中是否为空,如果popst为空,判断pushst是否为空,如果pushst不为空,将pushst中的元素入栈到popst中,最后返回popst的栈顶元素

int myQueuePeek(MyQueue* obj) //只取栈顶元素
{
    if(STEmpty(&obj->popst))
    {
        while(!STEmpty(&obj->pushst))
        {
            STPush(&obj->popst,STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    return STTop(&obj->popst);//popst中的栈顶元素,即pushst中的栈底元素
}

4、移除队列开头的元素,并返回队头元素
在这里插入图片描述

复用myQueuePeek函数,保存该函数的返回值,再出popst的栈顶元素

int myQueuePop(MyQueue* obj) //删数据 
{
    int front = myQueuePeek(obj);
    STPop(&obj->popst);
    return front;
}

5、判空
在这里插入图片描述

popst和pushst同时为空

bool myQueueEmpty(MyQueue* obj) 
{
    return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}

6、销毁

void myQueueFree(MyQueue* obj) 
{
    STDestroy(&obj->pushst);
    STDestroy(&obj->popst);
     free(obj);
}

整体代码:

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;//最开始不malloc空间
	//pst->top = -1;//指向栈顶元素
	pst->top = 0;//指向栈顶元素的下一个位置,表示已经有元素
	pst->capacity = 0;
}
void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}
void STPush(ST* pst, STDataType x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];//栈顶元素
}
bool STEmpty(ST* pst)
{
	return pst->top == 0;
}
int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}
typedef struct 
{
    ST pushst;
    ST popst;
} MyQueue;
MyQueue* myQueueCreate() 
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    if(obj==NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    STInit(&obj->pushst);
    STInit(&obj->popst);
    return obj;
}


void myQueuePush(MyQueue* obj, int x) 
{
    STPush(&obj->pushst,x);
}

int myQueuePop(MyQueue* obj) //删数据 
{
    int front = myQueuePeek(obj);
    STPop(&obj->popst);
    return front;
}

int myQueuePeek(MyQueue* obj) //只取栈顶元素
{
    if(STEmpty(&obj->popst))
    {
        while(!STEmpty(&obj->pushst))
        {
            STPush(&obj->popst,STTop(&obj->pushst));
            STPop(&obj->pushst);
        }
    }
    return STTop(&obj->popst);//popst中的栈顶元素,即pushst中的栈底元素
}

bool myQueueEmpty(MyQueue* obj) 
{
    return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}

void myQueueFree(MyQueue* obj) 
{
    STDestroy(&obj->pushst);
    STDestroy(&obj->popst);
     free(obj);
}

用队列实现栈

链接: link
题目描述:
在这里插入图片描述
在这里插入图片描述
题目思路:

题目中给我们两个队列实现一个栈,首先明确:
1、队列的性质:先进先出
2、栈的性质:后进先出

在这里插入图片描述

如何才能使用两个队列实现栈的后进先出?
本题给的两个队列就是用来导数据,进而实现栈的后进先出的性质

举例:如上图,如果说我们要出数据5,那么就需要将队列1当中的1 2 3 4 先入到队列2中,再出数据5,这样就实现了后进先出的性质。
在这里插入图片描述
注意:
如何入数据?
1、如果两个队列中的一个队列为空一个队列不为空,那么数据入到非空队列中
2、如果两个队列都为空,数据入到其中一个队列
分析:
1、栈的结构和栈的创建
在这里插入图片描述

方法1:给定MyStack栈中的两个队列都是结构体类型,直接malloc动态开辟一个栈的空间,里面存放队列1 q1和队列2 q2
初始化队列使用结构体指针。

在这里插入图片描述

方法2:给定MyStack栈中的两个队列都是结构体指针类型,动态开辟栈的空间,再动态开辟队列的空间,这样在初始化时就不需要进行取地址操作,因为q1和q2就是结构体指针类型。

在这里插入图片描述
2、入数据操作
在这里插入图片描述

1、如果q1不为空,那么就入队列1中
2、如果q2不为空,那么就入队列2中
3、如果两个都不为空,则随意入队列

void myStackPush(MyStack* obj, int x) 
{
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

3、出栈操作——倒数据

1、将非空队列的队头的数据导入空队列当中——入队
2、弹出非空队列的队头数据
3、取栈顶元素

int myStackPop(MyStack* obj) 
{
    Queue* qEmpty=&obj->q1;
    Queue* qNoneEmpty = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        Queue* qEmpty=&obj->q2;
        Queue* qNoneEmpty = &obj->q1;
    }
    while(QueueSize(qNoneEmpty)>1)
    {
        QueuePush(qEmpty,QueueFront(qNoneEmpty));
        QueuePop(qNoneEmpty);
    }
    int top = QueueFront(qNoneEmpty);
    QueuePop(qNoneEmpty);
    return top;
}

4、取栈顶元素——队尾元素

1、第一个队列不为空,就取队尾元素
2、反之取第二个队列的队尾元素

int myStackTop(MyStack* obj) 
{
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

5、判空

bool myStackEmpty(MyStack* obj) 
{
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

6、销毁

不仅释放栈,也要释放队列

void myStackFree(MyStack* obj) 
{
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

整体代码:

typedef int QDataType;
//每个节点的结构

typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;

//标识整个队列的结构
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;//队列的长度
}Queue;
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	
	//队列为空
	if (pq->ptail == NULL)
	{
		assert(pq->phead == NULL);
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		//队列不空
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}
void QueuePop(Queue* pq)
{
	//类似头删
	assert(pq);
	assert(!QueueEmpty(pq));
	//1、一个节点
	//2、多个节点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		//头删
		QNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	//return pq->size == 0;
	return pq->phead == NULL && pq->ptail == NULL;
}

typedef struct
{
    Queue q1;//队列1
    Queue q2;//队列2
} MyStack;


MyStack* myStackCreate()
{
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    if (obj == NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);
    return obj;
}

void myStackPush(MyStack* obj, int x) 
{
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) 
{
    Queue* qEmpty=&obj->q1;
    Queue* qNoneEmpty = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
       qEmpty=&obj->q2;
       qNoneEmpty = &obj->q1;
    }
    while(QueueSize(qNoneEmpty)>1)
    {
        QueuePush(qEmpty,QueueFront(qNoneEmpty));
        QueuePop(qNoneEmpty);
    }
    int top = QueueFront(qNoneEmpty);
    QueuePop(qNoneEmpty);
    return top;
}

int myStackTop(MyStack* obj) 
{
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

bool myStackEmpty(MyStack* obj) 
{
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) 
{
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
}

设计循环队列

链接: link
题目描述:
在这里插入图片描述
在这里插入图片描述
思路分析:
在这里插入图片描述

本题使用数组设计循环队列
1、假设循环队列存储k个数据,开k+1个空间,每次入队一个元素,rear指针都会指向该元素的后一个位置。

在这里插入图片描述
在这里插入图片描述

1、循环队列的结构

在这里插入图片描述

typedef struct 
{
    int front;
    int rear;
    int k;//队列中元素个数
    int* a;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a = (int*)malloc(sizeof(int*)*(k+1));
    obj->front=obj->rear = 0;
    obj->k=0;
    return obj;
}

2、判断循环队列为空:front=rear
在这里插入图片描述

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->rear==obj->front;
}

3、判断队列满:(rear+1)%(k+1)==front
在这里插入图片描述

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->rear+1)%(obj->k+1)==obj->front;

}

4、入数据

在rear位置入数据再让rear++,特殊情况:循环队列可能会绕回去,所以要判断rear的位置

在这里插入图片描述

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    if( myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->a[obj->rear]=value;
    obj->rear++;
    obj->rear%=(obj->k+1);//保证范围
}

5、出数据(删除数据)

判空,如果为空,则不进行删除操作
删除操作即让front++,并且保证front的范围

在这里插入图片描述

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
     if( myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
    obj->front%=(obj->k+1);//保证范围
    return true;
}

6、返回队头和队尾数据
在这里插入图片描述
在这里插入图片描述

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else if(obj->rear==0)
    {
        return obj->a[obj->rear+k-1];
    }
    else
    {
        return obj->a[obj->rear-1];
    }
}

整体代码:

typedef struct 
{
    int front;
    int rear;
    int k;//队列中元素个数
    int* a;
} MyCircularQueue;

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->rear==obj->front;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->rear+1)%(obj->k+1)==obj->front;

}
MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a = (int*)malloc(sizeof(int)*(k+1));
    obj->front=obj->rear = 0;
    obj->k=k;
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    if( myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->rear]=value;
    obj->rear++;
    obj->rear%=(obj->k+1);//保证范围
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
     if( myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
    obj->front%=(obj->k+1);//保证范围
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
   return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}



void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->a);
    free(obj);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
引用\[1\]提供了一个朴素的解法,使用两个栈来存储字符串,一个栈用来存储普通字符,另一个栈用来存储特殊字符。遍历字符串,如果是普通字符则压入第一个栈,如果是特殊字符则弹出第一个栈的栈顶元素。最后比较两个栈是否相同即可判断字符串是否有效。这个解法的时间复杂度是O(M + N),空间复杂度也是O(M + N)。\[1\] 引用\[2\]提供了另一个栈的应用场景,即判断括号是否有效。遍历字符串,如果是左括号则压入栈,如果是右括号则判断和栈顶元素是否匹配,不匹配则返回false,匹配则弹出栈顶元素。最后判断栈是否为空即可判断括号是否有效。\[2\] 引用\[3\]也提供了一个判断括号是否有效的解法,使用栈来操作。遍历字符串,如果是左括号则压入栈,如果是右括号则判断和栈顶元素是否匹配,不匹配则返回false,匹配则弹出栈顶元素。最后判断栈是否为空即可判断括号是否有效。这个解法使用了HashMap来存储括号的对应关系。\[3\] 综上所述,栈在解决字符串相关问题中有着广泛的应用,包括判断字符串是否有效、逆波兰表达式等。在解决这些问题时,栈可以帮助我们保存和处理字符的顺序,从而简化问题的处理过程。 #### 引用[.reference_title] - *1* *3* [Leetcode刷题03-栈](https://blog.csdn.net/weixin_47802917/article/details/123007699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] - *2* [leetCode-栈类型详解](https://blog.csdn.net/zhiyikeji/article/details/125508011)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Mikk-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值