【Leetcode】栈的性质与应用

20. 有效的括号

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。

左括号必须以正确的顺序闭合。

每个右括号都有一个对应的相同类型的左括号

示例1:

输入: s = " ( ) "
输出:true

示例2:

输入: s = " ( ) [ ] { } "
输出: true

示例3:

输入: s = " ( ] "
输出: false

提示

· 1 <= s.length <= 10 ^ 4
· s 仅由括号 ‘ () [ ] { } ’ 组成

bool isValid (char* s){
}

分析:

这道题可以用栈来写,但是目前还未学习C++,所以只能先手撕一个栈。

如果是左括号,进栈;如果是右括号,出栈里的左括号,进行匹配,匹配失败返回false。

题解:

//栈的操作
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<malloc.h>
#include<stdlib.h>

typedef int STDataType;
#define CAPACITY 4

typedef struct Stack {
	int* s;
	int top;
	int capacity;
}ST;

void STInit(ST* ps);//栈的初始化
void STDestroy(ST* ps);//栈的销毁
bool STEmpty(ST* ps);//判断栈是否为空
void STPush(ST* ps, STDataType x);//进行插入数据
void STPop(ST* ps);//删除数据
STDataType STTop(ST* ps);//寻找栈顶的数据
int STSize(ST* ps);//查看栈有几个元素


void STInit(ST* ps)
{
	assert(ps);//栈不能为空
	ps->s = (STDataType*)malloc(sizeof(STDataType) * CAPACITY);//malloc开辟空间
	if (ps->s == NULL)
	{
		perror("malloc fail");//开辟失败报错
		return;
	}
	ps->top = 0;//将top置为0,代表数据的个数。赋值为多少无所谓,看个人习惯
	ps->capacity = CAPACITY;//将容量先置为空
}

bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

void STDestroy(ST* ps)
{
	assert(ps);

	free(ps->s);//释放空间
	ps->s = NULL;//同时将指针置为空
    ps->top = 0;
    ps->capacity = 0;
}

void STPush(ST* ps, STDataType x)
{
	assert(ps);
	//要先检查容量,判断为不为满,满了进行扩容
	//如果扩容步骤使用很多次,就可以写个扩容函数,只有一次就没必要
	if (ps->top == ps->capacity)
	{
		STDataType* new = (STDataType*)realloc(ps->s, sizeof(STDataType) * ps->capacity * 2);
		if (new == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->s = new;
		ps->capacity *= 2;
	}
	ps->s[ps->top] = x;
	ps->top++;
}

void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));//如果栈为空的话,就不能进行删除
	ps->top--;//直接将个数减一就行了
}

STDataType STTop(ST* ps)
{
	assert(ps);
    assert(!STEmpty(ps));
	return ps->s[ps->top - 1];//返回元素减一的数据
}

int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}
//申请了动态空间要返回操作系统
//思路:遇到左括号就进栈,遇到右括号进行出栈匹配,若匹配失败返回false,直至字符指针指向空
bool isValid(char * s){
    ST st;
    STInit(&st);
    
    while (*s)
    {
        //遇到左括号进栈
        if (*s == '('
         || *s == '['
         || *s == '{')
         {
             STPush(&st, *s);
         }
         //遇到右括号出栈
        else
        {
            //如果第一个符号为右括号则直接返回false
            if (STEmpty(&st))
            {
                STDestroy(&st);
                return false;
            }
            //栈顶元素与右括号进行匹配
            if ((STTop(&st) != '(' && *s == ')')
              ||(STTop(&st) != '[' && *s == ']')
              ||(STTop(&st) != '{' && *s == '}'))
              {
                  STDestroy(&st);
                  return false;
              }
              //匹配成功就要删除栈顶元素,指向下一个元素
            STPop(&st);
           
        }
        s++;
    }  
    //如果只有一个左括号,就要判断栈里面是否为空,判空函数类型为bool类型
    //为空返回true,正好是正确的
    //不为空返回false,是错误的
    bool ret = STEmpty(&st);
    STDestroy(&st);
    return ret;

232. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾

int pop() 从队列的开头移除并返回元素

int peek() 返回队列开头的元素

boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。

你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可

示例1:

输入:
[“MyQueue”, “push”, “push”, “peek”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

1 <= x <= 9

最多调用 100 次 push、pop、peek 和 empty

假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

分析:

队列的性质是先进先出,栈的性质是后进先出,所以利用两个栈来实现队列的性质就可以了。例子:如果插入数据1 2 3 4,输出数据1 2 3 4,如何使栈实现这样的操作呢?
我们可以1 2 3 4存入到一个栈中,当要出数据时,存入另一个栈中,两个栈分别作为入栈和出栈的功能。
在这里插入图片描述

题解:

#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<malloc.h>
#include<stdlib.h>

typedef int STDataType;
#define CAPACITY 4

typedef struct Stack {
	int* s;
	int top;
	int capacity;
}ST;

void STInit(ST* ps);//栈的初始化
void STDestroy(ST* ps);//栈的销毁
bool STEmpty(ST* ps);//判断栈是否为空
void STPush(ST* ps, STDataType x);//进行插入数据
void STPop(ST* ps);//删除数据
STDataType STTop(ST* ps);//寻找栈顶的数据
int STSize(ST* ps);//查看栈有几个元素

void STInit(ST* ps)
{
	assert(ps);//栈不能为空
	ps->s = (STDataType*)malloc(sizeof(STDataType) * CAPACITY);//malloc开辟空间
	if (ps->s == NULL)
	{
		perror("malloc fail");//开辟失败报错
		return;
	}
	ps->top = 0;//将top置为0,代表数据的个数。赋值为多少无所谓,看个人习惯
	ps->capacity = CAPACITY;//将容量先置为空
}

bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->s);//释放空间
	ps->s = NULL;//同时将指针置为空
	ps->top = 0;
	ps->capacity = 0;
}

void STPush(ST* ps, STDataType x)
{
	assert(ps);
	//要先检查容量,判断为不为满,满了进行扩容
	//如果扩容步骤使用很多次,就可以写个扩容函数,只有一次就没必要
	if (ps->top == ps->capacity)
	{
		STDataType* new = (STDataType*)realloc(ps->s, sizeof(STDataType) * ps->capacity * 2);
		if (new == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->s = new;
		ps->capacity *= 2;
        
	}
	ps->s[ps->top] = x;
	ps->top++;
}

void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));//如果栈为空的话,就不能进行删除
	ps->top--;//直接将个数减一就行了
}

STDataType STTop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	return ps->s[ps->top - 1];//返回元素减一的数据
}

int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

typedef struct {
    ST emptyst;
    ST nonemptyst;
} MyQueue;

//队列的初始化
MyQueue* myQueueCreate() {
    MyQueue* newQueue = (MyQueue*)malloc(sizeof(MyQueue));
    if (newQueue == NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    //对栈进行初始化
    STInit(&newQueue->emptyst);
    STInit(&newQueue->nonemptyst);
    return newQueue;
}
//固定一个栈插入数据
void myQueuePush(MyQueue* obj, int x) {

        STPush(&obj->nonemptyst, x);
    
}

int myQueuePop(MyQueue* obj) {
    //如果出数据的栈为空,那么就要移除数据
    if (STEmpty(&obj->emptyst))//不加这个条件就会顺序混乱
    {
         while (STSize(&obj->nonemptyst))
        {
            STPush(&obj->emptyst, STTop(&obj->nonemptyst));
            STPop(&obj->nonemptyst);
        }
    }
   //不为空,直接出栈
    int top = STTop(&obj->emptyst);
    STPop(&obj->emptyst);
    return top;
}

int myQueuePeek(MyQueue* obj) {
    //出数据的栈为空,那么就要进行移数据
    if (STEmpty(&obj->emptyst))
    {
        while (STSize(&obj->nonemptyst))
        {
            STPush(&obj->emptyst, STTop(&obj->nonemptyst));
            STPop(&obj->nonemptyst);
        }
    }
    
    return STTop(&obj->emptyst);
}

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->emptyst) && STEmpty(&obj->nonemptyst);
}

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->emptyst);
    STDestroy(&obj->nonemptyst);
    free(obj);
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值