手撕算法题3 (附源码和思路)

news2024/9/20 18:46:00

算法

  • 1.有效的括号
  • 2.用队列实现栈
  • 3.用栈实现队列
  • 3.设计循环队列

1.有效的括号

在这里插入图片描述
有效的括号

思路
借助栈这样的数据结构,将所有左括号进行入栈,所有右括号与出栈的括号比较,相同循环继续,不同直接返回false。循环结束后检查栈是否为空,为空说明已经全部匹配了,若栈不为空说明并没有一一对应返回false,以上都没问题返回true。


设计程序
定义一个栈,字符串遍历若是左括号则入栈字符++,否则取栈顶元素出栈与此时的字符比较

(当然比较的条件这里我是用ASCII码写的,因为我查表发现它们的ASCII码差只为1或2),
注意取栈顶元素一定要栈不为空(如果此时栈为空说明绝对不匹配)

遍历完字符串,若果都一一对应了栈应该为空否则就不匹配,判断一下进行相应返回就行


编写代码

typedef char STDataType;
typedef struct Stack {
    STDataType* arr;
    int capacity; // 栈的空间大小
    int top;      // 栈顶
} ST;
void STInitialise(ST* ps) {
    assert(ps);
    ps->arr = NULL;
    ps->capacity = ps->top = 0;
}

void STDestroy(ST* ps) {
    assert(ps);
    if (ps->arr)
        free(ps->arr);
    ps->arr = NULL;
    ps->top = ps->capacity = 0;
}

void StackPush(ST* ps, STDataType x) {
    assert(ps);
    // 判断空间是否充足
    if (ps->top == ps->capacity) {
        // 增容//0*2 = 0
        // 若capacity为0,给个默认值,否则×2倍
        int NewCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
        STDataType* tmp =
            (STDataType*)realloc(ps->arr, NewCapacity * sizeof(STDataType));
        if (tmp == NULL) {
            perror("realloc fail!");
            exit(1);
        }
        ps->arr = tmp;
        ps->capacity = NewCapacity;
    }
    ps->arr[ps->top++] = x;
}

bool StackEmpty(ST* ps) {
    if (ps->top) {
        return true;
    }
    return false;
}

void StackPop(ST* ps) {
    assert(ps);
    assert(StackEmpty(ps));
    ps->top--;
}

STDataType StackTop(ST* ps) {
    assert(ps);
    assert(StackEmpty(ps));
    return ps->arr[ps->top - 1];
}
//
bool isValid(char* s) {
    char*tmp=s;
    ST ps;
    STInitialise(&ps);
    while(*tmp)
    {
        if(*tmp=='('||*tmp=='{'||*tmp=='[')
        {
            StackPush(&ps,*tmp);
        }
        else
        {
            if(!StackEmpty(&ps))
            return false;
            char top=StackTop(&ps);
            StackPop(&ps);
            if(*tmp-top!=1&&*tmp-top!=2)
            return false;
        }
        tmp++;
    }
    if(StackEmpty(&ps))
    return false;
    return true;
}

2.用队列实现栈

在这里插入图片描述
用队列实现栈

思路
在这里插入图片描述


设计程序

借助两个队列实现栈
在不为空的队列中入数据(都为空我们默认在q2入数据),
出栈我们定义好空栈和非空栈(会变化),将非空栈的size-1个元素导入空栈中,取空栈栈顶元素出栈
取栈顶元素直接返回非空队列的队尾元素


编写代码

typedef int QDataType;
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;
typedef struct Queue
{
	QueueNode* phead;
	QueueNode* ptail;
	int size;
}Queue;
void QueueInitialise(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	if (pq->phead == NULL && pq->ptail == NULL)
	{
		return false;
	}
	return true;
}
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* NewNode = (QueueNode*)malloc(sizeof(QueueNode));
	if (NewNode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	NewNode->data = x;
	NewNode->next = NULL;
	if (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));
	QueueNode* Next = pq->phead->next;
	if (pq->phead == pq->ptail)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	free(pq->phead);
	pq->phead = NULL;
	pq->phead = Next;
	pq->size--;
}
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(QueueEmpty(pq));
	return pq->ptail->data;
}
int QueueSize(Queue* pq)
{
	assert(pq);
	/*size_t size = 0;
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		size++;
		pcur = pcur->next;
	}*/
	return pq->size;
}
void QueueDestroy(Queue* pq)
{
	assert(pq);
	//assert(QueueEmpty(pq));

	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* Next = pcur->next;
		free(pcur);
		pcur = Next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(QueueEmpty(pq));
	return pq->phead->data;
}
///
typedef struct{
    Queue q1;
    Queue q2;
}MyStack;
MyStack* myStackCreate() {
    MyStack*pst=(MyStack*)malloc(sizeof(MyStack));
    QueueInitialise(&pst->q1);
    QueueInitialise(&pst->q2);

    return pst;
}

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

int myStackPop(MyStack* obj) {
    //找不为空的队列
    Queue*empQ=&obj->q1;
    Queue*noneQ=&obj->q2;
    if(QueueEmpty(&obj->q1))
    {
        noneQ=&obj->q1;
        empQ=&obj->q2;
    }
    while(QueueSize(noneQ)>1)
    {
        int front=QueueFront(noneQ);
        QueuePush(empQ,front);
        QueuePop(noneQ);
    }
    int pop=QueueFront(noneQ);
    QueuePop(noneQ);
    return pop;
}

int myStackTop(MyStack* obj) {
    if(QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    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);
    obj=NULL;
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);
 
 * int param_2 = myStackPop(obj);
 
 * int param_3 = myStackTop(obj);
 
 * bool param_4 = myStackEmpty(obj);
 
 * myStackFree(obj);
*/

3.用栈实现队列

在这里插入图片描述
用栈实现队列

思路
在这里插入图片描述
这样就实现了队列的先进先出了,程序思路大体与上述相同不过简单的是我们空队列和非空列是固定的。


编写代码

typedef int STDataType;
typedef struct Stack
{
	STDataType*arr;
	int capacity;//栈的空间大小
	int top;//栈顶
}ST;
void STInitialise(ST* ps)
{
	assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	//判断空间是否充足
	if (ps->top == ps->capacity)
	{
		//增容//0*2 = 0
		//若capacity为0,给个默认值,否则×2倍
		int NewCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, NewCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = NewCapacity;
	}
	ps->arr[ps->top++] = x;
}

bool StackEmpty(ST* ps)
{
	if (ps->top)
	{
		return true;
	}
	return false;
}

void StackPop(ST* ps)
{
	assert(ps);
	assert(StackEmpty(ps));
	ps->top--;
}

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(StackEmpty(ps));
	return ps->arr[ps->top - 1];
}

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

typedef struct {
    ST pushST;
    ST popST;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue*pst=(MyQueue*)malloc(sizeof(MyQueue));
    STInitialise(&pst->pushST);
    STInitialise(&pst->popST);

    return pst;
}

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

int myQueuePop(MyQueue* obj) {
    if(!StackEmpty(&obj->popST))
    {
        while(StackEmpty(&obj->pushST))
        {
            StackPush(&obj->popST,StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    int ret=StackTop(&obj->popST);
    StackPop(&obj->popST);
    return ret;
}

int myQueuePeek(MyQueue* obj) {
    if(!StackEmpty(&obj->popST))
    {
        while(StackEmpty(&obj->pushST))
        {
            StackPush(&obj->popST,StackTop(&obj->pushST));
            StackPop(&obj->pushST);
        }
    }
    return StackTop(&obj->popST);
}

bool myQueueEmpty(MyQueue* obj) {
    return !StackEmpty(&obj->pushST)&&!StackEmpty(&obj->popST);
}

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->pushST);
    STDestroy(&obj->popST);
    free(obj);
    obj=NULL;

}

/**
 * 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);
*/

3.设计循环队列

在这里插入图片描述
设计循环队列

思路
用数组实现循环队列,因为数组连续且不像链表需要自己去连接。其次数组实现的循环队列标识队列已满好实现,而链表实现的循环队列标识队列已满不好实现。

这就引出了这道题的难点怎么标识队列满了,接下来我们来实现

设计程序

在这里插入图片描述
rear=front时队列为空
在这里插入图片描述
(rear+1)%(capacity+1)==front我们表示为队列满了,比如我们队列的长度为4,多申请一个结点,当rare走到如图的黑色位置时(4+1)%(4+1)=0等于front此时就为空了,但是不是说当rare走到这个位置队列为满。
而是通过(rear+1)%(capacity+1)==front这个公式来判断是否为满,随着front的改变(队头出数据会导致front++),哨兵位置也会改变,但是我们申请的空间一定有一个结点来标识哨兵位。
我们对front++,rear++可能会越界它是一个循环队列所以要%=capacity,同时返回队尾元素,一定是rear-1,当rear为0减应该对应的元素为capacity的位置,如果是跟着我博客学习的粉丝可能对这道题有点遗憾,因为我们用链表实现队列的时候是返回队尾数据就直接返回了,不需要-1,但是严格来说队列不是只能队尾入数据吗而不是取数据,所以队尾是插入数据的地方而不是取数据的地方,希望这些能对大家有所帮助,如果还不能理解的话可以咨询博主。




typedef struct {
    int*arr;
    int front;
    int rear;
    int capacity;
} MyCircularQueue;


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

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->capacity+1) == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    return false;
    obj->arr[obj->rear++]=value;
    obj->rear%=obj->capacity+1;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    return false;
    obj->front++;
    obj->front%=obj->capacity+1;
    return true;
}

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

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    return -1;
    int prev = obj->rear-1;
    if(obj->rear==0)
    prev=obj->capacity;
    return obj->arr[prev];
}


void myCircularQueueFree(MyCircularQueue* obj) {
    obj->capacity=obj->front=obj->rear=0;
    free(obj->arr);
    obj->arr=NULL;
    free(obj);
    obj=NULL;
}

/**
 * Your MyCircularQueue struct will be instantiated and called as such:
 * MyCircularQueue* obj = myCircularQueueCreate(k);
 * bool param_1 = myCircularQueueEnQueue(obj, value);
 
 * bool param_2 = myCircularQueueDeQueue(obj);
 
 * int param_3 = myCircularQueueFront(obj);
 
 * int param_4 = myCircularQueueRear(obj);
 
 * bool param_5 = myCircularQueueIsEmpty(obj);
 
 * bool param_6 = myCircularQueueIsFull(obj);
 
 * myCircularQueueFree(obj);
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1967616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

模拟队列--C++

用数组来表示队列&#xff0c;怎么表示呢&#xff1f;我们先假设hh为头&#xff0c;tt为尾,当弹出队头的时候我们只需要把hh加一下就连可以了&#xff0c;相反tt一样也可以 #include<iostream> using namespace std; const int N1e510; int a[N],tt-1,hh0;//hh头 tt尾 i…

2.Linux_vi编辑器

打开/创建文件 1、打开/创建文件 指令&#xff1a;vi 文件名 若文件不存在&#xff0c;则新建一个文件&#xff1b;若文件存在&#xff0c;则打开这个文件。 2、打开文件时&#xff0c;指定光标的位置 指令&#xff1a;vi 文件名 行号 注意&#xff1a;""和行号…

吴恩达机器学习-C1W3L1-逻辑回归分类

在本实验中&#xff0c;您将对比回归和分类。 import numpy as np %matplotlib widget import matplotlib.pyplot as plt from lab_utils_common import dlc, plot_data from plt_one_addpt_onclick import plt_one_addpt_onclick plt.style.use(./deeplearning.mplstyle)分类…

JDK 8 升级 17 及 springboot 2.x 升级 3.x 指南

JDK 8 升级 17 简介 从 JDK 8 升级到 JDK 17 的过程中&#xff0c;有几个主要的变化&#xff0c;特别是 Java Platform Module System (JPMS) 的引入&#xff0c;以及一些包路径的调整。以下是与 JDK 17 相关的一些重要变化&#xff1a; Java Platform Module System (JPMS) …

The First项目报告:解读Trading Bot黑马,交易狙击手Banana Gun

Meme币市场的特点是高度投机性和波动性&#xff0c;一个项目可能在短时间内实现巨大涨幅&#xff0c;为投资者带来巨额回报。然而&#xff0c;这种市场也充满了不确定性&#xff0c;许多项目可能只是短暂的炒作&#xff0c;缺乏实际价值或长期发展的潜力。因此&#xff0c;对于…

实验2-4-3 求奇数分之一序列前N项和

//实验2-4-3 求奇数分之一序列前N项和#include<stdio.h> #include<math.h> int main(){int n;scanf("%d",&n);//输入正整数N&#xff1b;double sum0;for (int i 1; i < n * 2; i 2)/* 在表达式 for (int i 1; i < n * 2; i 2) 中&#x…

设计模式-策略模式的完整代码示例及测试验证

策略模式 什么是策略模式&#xff1f; 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以互换。 策略模式使得算法可以在不影响客户端的情况下发生变化。策略模式主…

研0 冲刺算法竞赛 day26 P1803 凌乱的yyy / 线段覆盖

P1803 凌乱的yyy / 线段覆盖 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 考点&#xff1a;线段覆盖 思路&#xff1a;将整体结束时间进行排序&#xff0c;在从头开始遍历计数 代码&#xff1a; #include<iostream> #include <algorithm> using namespace …

从零开始学习机器学习,掌握AI未来的关键!

从零开始学习机器学习 1. 介绍1.1 人工智能&#xff08;AI&#xff09;概述1.2 机器学习在人工智能中的应用1.3 机器学习基础概念 2. 监督学习2.1 什么是监督学习2.2 回归分析2.3 分类问题2.4 模型评估和选择 3. 无监督学习3.1 什么是无监督学习3.2 聚类算法3.3 降维技术 4. 深…

Spring源码解析(27)之AOP的核心对象创建过程2

一、前言 我们在上一节中已经介绍了Advisor的创建过程&#xff0c;当时我们创建的logUtil这bean&#xff0c;他在 resolveBeforeInstantiation返回的是null&#xff0c;那么就会继续往下执行doCreateBean方法。 二、源码分析 protected Object doCreateBean(String beanName,…

永结无间Ⅸ--你不需要LLM Agent

人们将目光锁定在下一个闪亮的事物上。FOMO 是人性的一部分。这也适用于企业。就像数据科学成为每个企业分析功能的热潮一样&#xff0c;Agentic Architecture 是大多数 AI 雷达上的热门目标。 但您是否考虑过您是否真的需要它&#xff1f; 实际情况是&#xff0c;您不需要 A…

解答|一年期HTTPS证书如何获取?

自2023年年底以来&#xff0c;各大平台陆续下架了一年期免费HTTPS证书&#xff0c;目前市面上已经不再提供一年期的免费证书。付费正式版证书成为首选&#xff01;而DV证书由于其低廉的价格广受个人或者中小企业的青睐。 下面是DV类型证书&#xff08;13个月时长&#xff09;的…

防火墙Firewalld(iptables)

目录 一、Linux防火墙基础 1.什么是防火墙 2.防火墙的功能 3.防火墙的类型 二、Linux防火墙工具 1.iptables 2. netfilter 3.四表五链结构 3.1四表 3.2五链 3.3总结 4.数据包过滤的匹配流程 4.1规则表之间的顺序 4.2规则链之间的顺序 4.3规则链内的匹配顺序 …

人数管控系统助力图书馆实现精准客流统计分析

一、客流统计痛点在图书馆的日常运营中&#xff0c;客流统计面临着诸多难题。传统的人工计数方法不仅耗费人力&#xff0c;而且数据准确性难以保证。无法精确掌握不同时间段的读者流量&#xff0c;导致图书馆在资源配置和服务安排上缺乏科学依据。难以了解各个区域的受欢迎程度…

查看RAM和Flash

0 Preface/Foreword 1 查看方法 1.1 map文件中查看 1.1.1 RAM可用情况 在map文件中&#xff0c;搜索字符串&#xff1a;free_ramcp 该字段表示剩余可用的RAM大小&#xff0c;前面对应的是hexadecimal的数值&#xff08;单位Byte&#xff09;&#xff0c;就是剩余可用的RA…

浅谈ArkTS/ArkUI组件开发

浅谈ArkTS/ArkUI组件开发 本篇文章将从一个移动开发思维的维度出发&#xff0c;浅谈ArkTS组件开发的基础问题&#xff0c;比如状态管理、装饰器、属性传递、自定义构建函数、插槽、条件渲染&#xff0c;模块引用和路由跳转等。 创建项目 这里使用截图简单过一下&#xff0c;不…

数据结构与算法 - 递归

一、递归 1. 概述 定义&#xff1a;在计算机科学中&#xff0c;递归是一种解决计算问题的方法&#xff0c;其中解决方案取决于同一类问题的更小子集。 比如单链表递归遍历的例子&#xff1a; void f(Node node) {if(node null) {return;}println("before:" node…

Java 字符串常量池

目录 一、池化概念 二、字符串常量池 1. 概述 2. String对象的创建过程 1&#xff09;直接使用字符串常量进行赋值 2&#xff09;通过new创建String类对象 3&#xff09;结论 4&#xff09;intern方法 一、池化概念 先看如下的一段代码&#xff1a; String s1 "…

LLM实战系列(1)—强强联合Langchain-Vicuna应用实战

背景 本文主要介绍一下&#xff0c;基于Langchain与Vicuna-13B的外挂OceanBase知识库项目实战以及QA使用&#xff0c;项目地址: github.com/csunny/DB-G… 在开始之前&#xff0c;我们还是先看看效果&#xff5e; 自Meta发布LLaMA大模型以来&#xff0c; 围绕LLaMA微调的模型…

为什么越来越多的IT青年转行网络安全?

目前&#xff0c;我国互联网已经从爆发增长期进入平稳发展阶段&#xff0c;同时每年大量计算机相关专业的毕业生涌入就业市场&#xff0c;导致IT行业逐渐趋于饱和状态&#xff0c;甚至出现裁员现象&#xff0c;去年很多大厂都有裁员&#xff0c;不少程序员再就业成了难题。 面…