思维导图:
1.匹配括号
题目如下:
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
题目链接:https://leetcode.cn/problems/valid-parentheses/
接口:
bool isValid(char * s){
}
分析:
根据题目的意思,当相邻最近的左括号与右括号匹配到一块才能被叫做有效的括号。当左右括号不匹配时就要返回false。根据栈的后进先出的特点,我们可以将左括号入栈,然后在遇到右括号时就出一个左括号来与右括号匹配。这样一定可以实现相邻最近的两个左右括号的匹配。
代码:
1.首先要建立一个栈
typedef char DataType;
typedef struct ST
{
DataType* a;//数组指针
int Top;//栈顶指针
int capaCity;//容量
}ST;
void STinit(ST* stack)
{
assert(stack);
assert(stack->a);
stack->a = NULL;
stack->Top = 0;
stack->capaCity = 0;
}
void STpush(ST* stack,int x)
{
assert(stack);
if (stack->capaCity == stack->Top)//扩容操作
{
int newCapacity = stack->capaCity == 0 ? 4 : 2 * stack->capaCity;
stack->a = (DataType*)realloc(stack->a, newCapacity * sizeof(DataType));
if (stack->a == NULL)
{
perror("realloc fail");
return ;
}
stack->capaCity = newCapacity;
}
stack->a[stack->Top] = x;
stack->Top++;
}
bool STEmpty(ST* stack)
{
assert(stack);
return stack->Top == 0;
}
void STPop(ST* stack)
{
assert(stack);
assert(!STEmpty(stack));
stack->Top--;
}
DataType STFront(ST* stack)
{
assert(stack);
assert(stack->a);
DataType* front = stack->a[stack->Top - 1];
return front;
}
void STDestory(ST* stack)
{
assert(stack);
free(stack->a);
stack->Top = stack->capaCity = 0;
}
2.写匹配代码
括号的匹配的代码的思路是左括号入栈。当遇到右括号时就出栈顶的左括号与右括号进行过匹配。匹配时分三种情况:
1.当不匹配时直接返回false
2.当先出现右括号时直接不匹配
3.当遍历完字符串以后栈内还有左括号,那左括号与右括号的数量关系就是不对等的,返回false.
bool isValid(char * s){
ST stack;
STinit(&stack);
while(*s)
{
if(*s == '('||*s=='{'||*s=='[')
{
STpush(&stack,*s);//当*s为左括号时就入栈
}
else
{ //当遇到右括号时比较,比较分三种情况
if(STEmpty(&stack))//当右括号先出现时一定匹配不成功
{
STDestory(&stack);
return false;
}
char Top = STTop(&stack);
STPop(&stack);
if(*s==']')
{
if(Top=='{'||Top=='(')
{
STDestory(&stack);
return false;
}
}
if(*s=='}')
{
if(Top=='('||Top=='(')
{
STDestory(&stack);
return false;
}
}
if(*s==')')
{
if(Top=='{'||Top=='[')
{
STDestory(&stack);
return false;
}
}
}
s++;
}
if(!STEmpty(&stack))//当栈内的左括号还没有出完,那左右括号的数量就不是相同的
{
STDestory(&stack);
return false;
}
return true;
}
2,用栈实现队列
题目:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
题目链接:https://leetcode.cn/problems/implement-queue-using-stacks/
题目接口:
typedef struct {
} MyQueue;
MyQueue* myQueueCreate() {
}
void myQueuePush(MyQueue* obj, int x) {
}
int myQueuePop(MyQueue* obj) {
}
int myQueuePeek(MyQueue* obj) {
}
bool myQueueEmpty(MyQueue* obj) {
}
void myQueueFree(MyQueue* obj) {
}
分析:
先想想栈与队列的差别:栈是后进先出的,队列是先进先出的。我们该如何改变栈的后进先出的顺序将其改成先进先进先出呢?答案是通过两个栈来交换:
我们该如何来利用两个Stack来改变顺序呢?答案就是将Stack1中的数据从栈顶按顺序导入到Stack2中,这样栈顶元素就变成了栈底元素了。
显然当我们要出数据时只要出Stack2中的数据便可以了。所以又可以将Stack2改名叫PopStack,Stack1改名叫做PushStack.根据以上逻辑写出代码如下:
先创建栈:
typedef int DataType;
typedef struct ST
{
DataType* a;//数组指针
int Top;//栈顶指针
int capaCity;//容量
}ST;
void STinit(ST* stack)
{
assert(stack);
assert(stack->a);
stack->a = NULL;
stack->Top = 0;
stack->capaCity = 0;
}
void STpush(ST* stack,int x)
{
assert(stack);
if (stack->capaCity == stack->Top)//扩容操作
{
int newCapacity = stack->capaCity == 0 ? 4 : 2 * stack->capaCity;
stack->a = (DataType*)realloc(stack->a, newCapacity * sizeof(DataType));
if (stack->a == NULL)
{
perror("realloc fail");
return ;
}
stack->capaCity = newCapacity;
}
stack->a[stack->Top] = x;
stack->Top++;
}
bool STEmpty(ST* stack)
{
assert(stack);
return stack->Top == 0;
}
void STPop(ST* stack)
{
assert(stack);
assert(!STEmpty(stack));
stack->Top--;
}
DataType STFront(ST* stack)
{
assert(stack);
assert(stack->a);
DataType* front = stack->a[stack->Top - 1];
return front;
}
void STDestory(ST* stack)
{
assert(stack);
free(stack->a);
stack->Top = stack->capaCity = 0;
}
解题代码:
typedef struct {//定义队列结构
ST PopStack;
ST PushStack;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));//动态开辟出一个MyQueue
if(obj == NULL)
{
perror("malloc fail");
return;
}
STinit(&obj->PopStack);//初始化MyQueue里的队列
STinit(&obj->PushStack);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
STpush(&obj->PushStack,x);//插入数据只能往PushStack里插入
}
int myQueuePeek(MyQueue* obj) {
if(STEmpty(&obj->PopStack)){//当PopStack里的数据为空时往里面插入PushStack里的数据
while(!STEmpty(&obj->PushStack))
{
int Top = STFront(&obj->PushStack);
STpush(&obj->PopStack,Top);
STPop(&obj->PushStack);
}
}
int front = STFront(&obj->PopStack);
// STPop(&obj->PopStack);
return front;
}
int myQueuePop(MyQueue* obj) {
int front = myQueuePeek(obj);
STPop(&obj->PopStack);
return front;
}
bool myQueueEmpty(MyQueue* obj) {//两个栈为空才是空
return STEmpty(&obj->PopStack)&&STEmpty(&obj->PushStack);
}
void myQueueFree(MyQueue* obj) {
//销毁操作,销毁三者
STDestory(&obj->PopStack);
STDestory(&obj->PushStack);
free(obj);
}
3.用队列实现栈
题目:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
题目链接: https://leetcode.cn/problems/implement-stack-using-queues/
题目接口:
typedef struct {
} MyStack;
MyStack* myStackCreate() {
}
void myStackPush(MyStack* obj, int x) {
}
int myStackPop(MyStack* obj) {
}
int myStackTop(MyStack* obj) {
}
bool myStackEmpty(MyStack* obj) {
}
void myStackFree(MyStack* obj) {
}
分析:
用队列来实现栈还是像用栈实现队列一样,还是用两个队列来实现一个栈。就是用两者倒来倒去。只是这时不能够定义两个有特定功能的队列来分别实现插入与删除的操作。在用队列实现栈时要往有数据的队列里插入数据。出数据时要将不是空的的队列里的数据搞到不是空的队列里面。然后再来出数据。
代码:
创建队列代码:
typedef int Datatype;
typedef struct Qnode {
struct Qnode* next;
Datatype val;
}Qnode;
typedef struct Queue {
Qnode* phead;
Qnode* ptail;
int size;
}Queue;
void QueueInit(Queue* pc)
{
assert(pc);
pc->phead = NULL;
pc->ptail = NULL;
pc->size = 0;
}
void PushQueue(Queue* pc,Datatype x)
{
assert(pc);
Qnode* newnode = (Qnode*)malloc(sizeof(Qnode));
if (newnode == NULL)
{
perror("malloc fail/n");
return;
}
newnode->val = x;
newnode->next = NULL;
if (pc->phead == NULL)
{
//assert(pc->ptail );
pc->phead = newnode;
pc->ptail = newnode;
}
else
{
pc->ptail->next = newnode;
pc->ptail = newnode;
}
pc->size++;
}
bool QEmpty(Queue* pc)
{
return pc->phead == NULL;
}
void PopQueue(Queue* pc)//分一个节点和多个节点两种情况
{
assert(pc);
assert(!QEmpty(pc));
if(pc->phead->next==NULL)
{
free(pc->phead);
pc->phead = pc->ptail;
}
else
{
Queue* next = pc->phead->next;
free(pc->phead);
pc->phead = next;
}
pc->size--;
}
Datatype QueueFront(Queue* pc)
{
assert(pc);
assert(pc->phead);
Datatype val = pc->phead->val;
return val;
}
Datatype QueueBack(Queue* pc)
{
assert(pc);
assert(pc->ptail);
Datatype val = pc->ptail->val;
return val;
}
int Qsize(Queue* pc)
{
int size = pc->size;
return size;
}
void QDestory(Queue* pc)
{
assert(pc);
Qnode* cur = pc->phead;
while (cur)
{
Qnode* next = cur->next;
free(cur);
cur = next;
}
pc->phead = NULL;
pc->ptail = NULL;
pc->size = 0;
}
解题代码:
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
QInit(&obj->q1);
QInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) {//往非空队列里导数据
if(!QueueEmpty(&obj->q1))
{
QPush(&obj->q1,x);
}
else{
QPush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {//移动非空队列里的数据到空队列中直至原来的非空队列中只剩一个数据然后删除再返回那一个数据
Queue* Empty = &obj->q1;
Queue* noEmpty = &obj->q2;
if(!QueueEmpty(&obj->q1))
{
noEmpty = &obj->q1;
Empty = &obj->q2;
}
while(QSize(noEmpty)>1)
{
int front = QFront(noEmpty);
QPush(Empty,front);
QPop(noEmpty);
}
int Top = QFront(noEmpty);
QPop(noEmpty);
return Top;
}
int myStackTop(MyStack* obj) {
if(!QueueEmpty(&obj->q1))
{
return QBack(&obj->q1);
}
else
{
return QBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
QDestory(&obj->q1);
QDestory(&obj->q2);
free(obj);
}