栈的2道面试题【有效的括号】【用栈实现队列】

栈的面试题:

1.有效的括号

题目:

有效的括号

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

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

思路:

  1. 首先我们可以知道我们需要去比较字符串内的元素,并且我们需要用到后进先出的场景,因此这里我们考虑用栈来解决问题
  2. 我们将前括号放到栈内,s指针如果指向的是后括号,就让其和栈内的栈顶元素对比,如果匹配就将栈顶元素弹出,s继续遍历
  3. 一旦不匹配,或者栈空了,s还有后括号没有匹配,或者栈还有元素,s没有后括号匹配了就是无效字符串,返回false

代码实现:

由于我们是使用C语言写oj题,因此我们需要自己去编写栈的定义和栈的接口实现

如果是在leetcode上,头文件之类的自己会包含,我们不用去管

接口:
// 这里的栈我们用动态顺序表实现 (也可以用静态顺序表实现[不好扩容和定义空间大小])
# include<stdio.h>
# include<assert.h>
# include<stdlib.h>
# include<stdbool.h>

typedef char SLDataType;
typedef struct Stack
{
	SLDataType* _a;
	int _top; // 栈顶下标 [规定栈顶下标:最后一个有效数据的下一个位置]
	int _capacity; // 数组的有效空间大小 
}Stack;


// 栈的初始化
void StackInit(Stack* ps);

// 栈的销毁
void StackDestory(Stack* ps);

// 栈是能从栈顶  存数据或者取数据,因此不存在尾插头插之类的
// 入栈
void StackPush(Stack* ps, SLDataType x);

// 出栈
void StackPop(Stack* ps);

// 栈的数据个数获取
//int StackSize(Stack st); //其实理论上获取元素个数只需要传值调用就行 但是为了保持接口一致性,我们采用指针
int StackSize(Stack* ps);

// 获取栈顶元素
SLDataType StackTop(Stack* ps);

// 判断栈是否为空
int StackEmpty(Stack* ps); // 是空返回1  不是空的返回0

// 栈的初始化
void StackInit(Stack* ps)
{
	assert(ps); // ps不能为NULL

	// 栈的初始化
	/*ps->_a = NULL;
	ps->_top = 0;
	ps->_capacity = 0;*/

	// 除了上面这种初始化。也可以这样初始化
	SLDataType* tmp = (SLDataType*)malloc(sizeof(SLDataType) * 4); // 这样后面入栈时无需判断 空间是否为0 
	if (tmp == NULL)
	{
		perror("StackInit():malloc()");
		return;
	}

	ps->_a = tmp;
	ps->_top = 0;
	ps->_capacity = 4;
}

// 栈的销毁
void StackDestory(Stack* ps)
{
	assert(ps);

	free(ps->_a);
	ps->_a = NULL;

	ps->_top = ps->_capacity = 0;
}

// 入栈
void StackPush(Stack* ps, SLDataType x)
{
	assert(ps);

	// 插入之前 判断栈的空间是否足够新的数据插入
	if (ps->_top == ps->_capacity) // 判断空间是否足够 
	{
		int newcapacity = ps->_capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->_a, sizeof(SLDataType) * newcapacity); // 增容
		if (tmp == NULL) // 判断是否增容成功
		{
			perror("StackPush():realloc()");
			return;
		}

		// 更新栈
		ps->_a = tmp;
		ps->_capacity = newcapacity;
	}

	ps->_a[ps->_top] = x; // 入栈
	ps->_top++; // 让top记录的是栈顶 也就是最后一个数据的下一个位置
}

// 出栈
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0); // 栈里面要有数据才能出栈

	ps->_top--; // 让top--就行 最后一个数据的下标是 top - 1
}

// 栈的数据个数获取
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->_top; // top代表栈顶下标,是最后的一个数据的下标 + 1  其实就是栈的数据个数
}

// 获取栈顶元素
SLDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0); // 没有数据还怎么获取

	return ps->_a[ps->_top - 1]; // top是栈顶下标,top - 1才是最后一个数据的下标
}

// 判断栈是否为空
int StackEmpty(Stack* ps) // 是空返回1  不是空的返回0
{
	assert(ps);

	return ps->_top == 0 ? 1 : 0; // ps->pos只要为0就说明栈内没有数据了
	//return !ps->_top; // ps->top 为0 就返回1,为真就返回 0 ,除了0的数都是真
}
代码:
bool isValid(char* s)
{
    // 由于这道题需要用到后进先出的特性,因此我们使用栈来解决
    // 创建一个栈
    Stack st;
    StackInit(&st); // 初始化
    bool ret = true; // 用来判断字符串是否有效

    // 遍历字符串
    while (*s != '\0')
    {
        // 如果s指针指向的是前括号就入栈
        if (*s == '(' || *s == '[' || *s == '{')
        {
            StackPush(&st, *s);
            s++; // 让s往后走
        }
        else
        {
            // 走到这里有可能是s后括号多,栈内已经没有前括号了,那后面去取栈顶元素自然无法取出
            if (StackEmpty(&st))// 判断栈是否空了
            {
                // 走进来就说明栈内没有元素了,但是s还有后括号
                ret = false; // 无效字符串
                break;
            }
            // 判断s下一步指向的是否是后括号,是否匹配栈顶的前括号
            char top = StackTop(&st); // 取出栈顶元素
            // 每一种括号都要判断一下是否匹配到
            if (*s == ')' && top != '(')
            {
                // 走到这里说明没有匹配上
                ret = false; // 无效字符串
                break; // 不在这里return false是因为会有内存泄漏问题,跳出循环去外面统一调用销毁函数
            }
            if (*s == ']' && top != '[')
            {
                // 走到这里说明没有匹配上
                ret = false; // 无效字符串
                break;
            }
            if (*s == '}' && top != '{')
            {
                // 走到这里说明没有匹配上
                ret = false; // 无效字符串
                break;
            }

            // 走到这里说明有括号配对成功,让s继续往后遍历
            s++;
            // 栈顶元素匹配成功之后要弹出来,防止后面还有括号要配对
            StackPop(&st);
        }

    }
    // 走到这里,有可能是全部匹配完是true。 
    //也有可能是s字符串只有前括号比后括号多 退出循环时,栈内还有许多前括号
    if (!StackEmpty(&st)) // 判断栈是否为空
        ret = false; // 不是空的就是无效字符串

    StackDestory(&st); // 销毁栈

    if (ret == false)
        return false;

    // 走到这里就说明是有效字符串
    return true;
}

2.用栈实现队列

题目:

用栈实现队列

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

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

思路:

  1. 要通过两个栈实现先进先出的队列,我们要思考数据转移的特性

  2. 我们发现,我们把栈的数据转移到另外一个栈的时候,数据的顺序会倒转

  3. image-20240507223619789

  4. image-20240507223635988

  5. 然后我们发现,这样就是先进先出了,1,2, 3, 4压进去,出来也是从栈顶出来,1, 2, 3, 4。 也就是说 第一个栈的栈顶就是队列的队尾,第二个栈的栈顶就是队列的队头。

    • 那我们给这个队列插入数据时候,要从队尾插入,也就是要把数据从第二个栈全部转移到第一个栈。
    • 队列导出数据的时候,也就是从队头出,那就要把数据从第一个栈全部转移到第二个栈。

代码实现:

接口:
// 这里的栈我们用动态顺序表实现 (也可以用静态顺序表实现[不好扩容和定义空间大小])

typedef int SLDataType;
typedef struct Stack
{
	SLDataType* _a;
	int _top; // 栈顶下标 [规定栈顶下标:最后一个有效数据的下一个位置]
	int _capacity; // 数组的有效空间大小 
}Stack;


// 栈的初始化
void StackInit(Stack* ps);

// 栈的销毁
void StackDestory(Stack* ps);

// 栈是能从栈顶  存数据或者取数据,因此不存在尾插头插之类的
// 入栈
void StackPush(Stack* ps, SLDataType x);

// 出栈
void StackPop(Stack* ps);

// 栈的数据个数获取
//int StackSize(Stack st); //其实理论上获取元素个数只需要传值调用就行 但是为了保持接口一致性,我们采用指针
int StackSize(Stack* ps);

// 获取栈顶元素
SLDataType StackTop(Stack* ps);

// 判断栈是否为空
int StackEmpty(Stack* ps); // 是空返回1  不是空的返回0

// 栈的初始化
void StackInit(Stack* ps)
{
	assert(ps); // ps不能为NULL

	// 栈的初始化
	/*ps->_a = NULL;
	ps->_top = 0;
	ps->_capacity = 0;*/

	// 除了上面这种初始化。也可以这样初始化
	SLDataType* tmp = (SLDataType*)malloc(sizeof(SLDataType) * 4); // 这样后面入栈时无需判断 空间是否为0 
	if (tmp == NULL)
	{
		perror("StackInit():malloc()");
		return;
	}

	ps->_a = tmp;
	ps->_top = 0;
	ps->_capacity = 4;
}

// 栈的销毁
void StackDestory(Stack* ps)
{
	assert(ps);

	free(ps->_a);
	ps->_a = NULL;

	ps->_top = ps->_capacity = 0;
}

// 入栈
void StackPush(Stack* ps, SLDataType x)
{
	assert(ps);

	// 插入之前 判断栈的空间是否足够新的数据插入
	if (ps->_top == ps->_capacity) // 判断空间是否足够 
	{
		int newcapacity = ps->_capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->_a, sizeof(SLDataType) * newcapacity); // 增容
		if (tmp == NULL) // 判断是否增容成功
		{
			perror("StackPush():realloc()");
			return;
		}

		// 更新栈
		ps->_a = tmp;
		ps->_capacity = newcapacity;
	}

	ps->_a[ps->_top] = x; // 入栈
	ps->_top++; // 让top记录的是栈顶 也就是最后一个数据的下一个位置
}

// 出栈
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0); // 栈里面要有数据才能出栈

	ps->_top--; // 让top--就行 最后一个数据的下标是 top - 1
}

// 栈的数据个数获取
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->_top; // top代表栈顶下标,是最后的一个数据的下标 + 1  其实就是栈的数据个数
}

// 获取栈顶元素
SLDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0); // 没有数据还怎么获取

	return ps->_a[ps->_top - 1]; // top是栈顶下标,top - 1才是最后一个数据的下标
}

// 判断栈是否为空
int StackEmpty(Stack* ps) // 是空返回1  不是空的返回0
{
	assert(ps);

	return ps->_top == 0 ? 1 : 0; // ps->pos只要为0就说明栈内没有数据了
	//return !ps->_top; // ps->top 为0 就返回1,为真就返回 0 ,除了0的数都是真
}

代码(自己实现的版本):
typedef struct 
{
    Stack _s1;
    Stack _s2;    
} MyQueue;


MyQueue* myQueueCreate() 
{
    // 创建栈
    MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&pq->_s1);
    StackInit(&pq->_s2);

    return pq;
}

void myQueuePush(MyQueue* obj, int x) 
{
    // 给队列插入元素,要在第一个栈插入
    // 如果第二个栈有数据,要将其全部转移到第一个栈
    if(!StackEmpty(&obj->_s2))
    {
        // 第二个栈的数据有数据,将其全部转移到第一个栈
        while(StackSize(&obj->_s2) > 0)
        {
            // 转移
            StackPush(&obj->_s1, StackTop(&obj->_s2));
            // 让第二个栈的数据出栈
            StackPop(&obj->_s2);
        }
    }

    // 走到这里,如果第二个栈有数据,也全部转移到第一个栈
    // 如果第二个栈没有数据,那就直接在第一个栈插入数据就好
    StackPush(&obj->_s1, x);    
}

int myQueuePop(MyQueue* obj) 
{
    // 要找到队头(队列开头的元素)就要把全部数据都放在第二个栈,栈顶的数据就是队头
    if(!StackEmpty(&obj->_s1)) 
    {
        // 第一个栈的数据有数据,将其全部转移到第二个栈
        while(StackSize(&obj->_s1) > 0)
        {
            // 转移
            StackPush(&obj->_s2, StackTop(&obj->_s1));
            // 让第一个栈的数据出栈
            StackPop(&obj->_s1);
        }
    }
    // 由于题目说了一个空的队列不会调用 pop 或者 peek 操作
    // 因此这里不用判断两个栈是否为空

    // 走到这里数据一定在第二个栈
    int ret = StackTop(&obj->_s2);
    StackPop(&obj->_s2); // 移除元素
    return ret;
}

int myQueuePeek(MyQueue* obj) 
{
      // 要找到队头(队列开头的元素)就要把全部数据都放在第二个栈,栈顶的数据就是队头
    if(!StackEmpty(&obj->_s1))
    {
        // 第一个栈的数据有数据,将其全部转移到第二个栈
        while(StackSize(&obj->_s1) > 0)
        {
            // 转移
            StackPush(&obj->_s2, StackTop(&obj->_s1));
            // 让第一个栈的数据出栈
            StackPop(&obj->_s1);
        }
    }
    // 由于题目说了一个空的队列不会调用 pop 或者 peek 操作
    // 因此这里不用判断两个栈是否为空

    // 返回队头,也就是第二个栈的栈顶数据
    return StackTop(&obj->_s2);
}

bool myQueueEmpty(MyQueue* obj) 
{
    // 如果两个栈都为空,队列才是空
    return StackEmpty(&obj->_s1) && StackEmpty(&obj->_s2);
}

void myQueueFree(MyQueue* obj) 
{
    StackDestory(&obj->_s1);
    StackDestory(&obj->_s2);

    free(obj);
    obj = NULL;
}
优化后的代码:
typedef struct 
{
    Stack _pushST; // 用于插入数据
    Stack _popST; // 用于出数据
} MyQueue;


MyQueue* myQueueCreate() 
{
    // 创建栈
    MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&pq->_pushST);
    StackInit(&pq->_popST);

    return pq;
}

void myQueuePush(MyQueue* obj, int x) 
{
    // 直接把数据插入到pushST栈内
    StackPush(&obj->_pushST, x);
}

int myQueuePop(MyQueue* obj) 
{
    // 这个函数的功能和peek函数的功能就多了一个要移除,也就是让队头数据弹出
    // 那我们就考虑让代码复用
    int ret = myQueuePeek(obj);
    StackPop(&obj->_popST); // 代码复用
    return ret;
}

int myQueuePeek(MyQueue* obj) 
{
    // 要找到队头 也就是popST的栈顶数据
    // 要分两种情况,
    //1.如果popST栈没有数据,那就把pushST栈的数据转移到popST栈内
    //2.如果popST有数据,直接返回栈顶的数据,这个数据就是队头
    if(!StackEmpty(&obj->_popST))
    {
        // popST有数据,直接返回栈顶数据,就是队头
        return StackTop(&obj->_popST);
    }
    else
    {
        // popST为空,将pushST栈的数据转移到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) 
{
    StackDestory(&obj->_popST);
    StackDestory(&obj->_pushST);

    free(obj);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CAN报文中的信号解析

ECU发送的一帧CAN报文中是有多个信号的。信号在报文的数据域中&#xff0c;数据域中可以有多个信号。协议规范一帧CAN报文数据域最多有8个字节&#xff0c;企业中一般都设计为所有的CAN报文都是8字节。8个字节&#xff08;B&#xff09;换算成比特&#xff08;bit&#xff09;就…

内网穿透使用教程

什么是内网穿透 内网穿透&#xff0c;即NAT穿透&#xff0c;网络连接时术语&#xff0c;计算机是局域网内时&#xff0c;外网与内网的计算机节点需要连接通信&#xff0c;有时就会出现不支持内网穿透。就是说映射端口&#xff0c;能让外网的电脑找到处于内网的电脑&#xff0c…

一文让您了解离散制造中的制造执行系统 ​​(MES)

什么是制造执行系统 ​​(MES)&#xff1f; 制造执行系统&#xff08;通常称为MES&#xff09;是一种综合软件解决方案&#xff0c;旨在监视、控制和管理车间的制造运营。MES 充当企业级系统&#xff08;如企业资源规划或 ERP&#xff09;与制造环境中发生的实时流程之间的桥梁…

【设计模式】之观察者模式

系列文章目录 【设计模式】之装饰器模式【设计模式】之工厂模式&#xff08;三种&#xff09;【设计模式】之工厂模式&#xff08;三种&#xff09; 前言 今天给大家介绍另一种设计模式--观察者模式&#xff0c;有了解webscoket实现原理的小伙伴应该对这个设计模式不陌生。不清…

《视觉十四讲》例程运行记录(3)——运行ch6的例程中Ceres和g2o库的安装

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、安装Ceres1. 安装依赖2. 编译安装 二、安装g2o1. 安装依赖项2. 编译安装3. 可能出现的报错(1) 报错一 一、安装Ceres 1. 安装依赖 终端输入&#xff1a; sud…

21 使用Hadoop Java API读取序列化文件

在上一个实验中我们筛选了竞赛网站日志数据中2021/1和2021/2的数据以序列化的形式写到了hdfs上。 接下来我们使用Java API 读取序列化的数据保存到磁盘中。 其他命令操作请参考&#xff1a;16 Java API操作HDFS-CSDN博客 1.我直接在上一个项目中test/java目录下创建com.maidu.s…

72207-80-8,Epoxide-PEG-Epoxide是一种具有两个环氧基团的线性双功能PEG(聚乙二醇)试剂

【试剂详情】 英文名称 Ep-PEG-Ep&#xff0c;Epoxide-PEG-Epoxide 中文名称 环氧基-聚乙二醇-环氧基&#xff0c;聚乙二醇二缩水甘油醚 CAS号 72207-80-8 外观性状 由分子量决定&#xff0c;固体或者液体。 分子量 0.4k&#xff0c;0.6k&#xff0c;1k&#xff0c;2k…

代码训练LeetCode(17)存在重复元素

代码训练(17)LeetCode之存在重复元素 Author: Once Day Date: 2024年5月7日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 219. 存在重复元素 II - 力扣&#xff08;LeetCode&#xff09;力扣 (LeetCode) 全球…

windows端口复用

1. 概述 使用 HTTP.sys 中的 Net.tcp Port Sharing 服务&#xff0c;配合 WinRM 实现端口复用。 优点&#xff1a; HTTP.sys 为 windows 原生机制&#xff0c; WinRM 为 windows 自带功能&#xff0c;动作较小&#xff0c;不易触发主 动防御。 需要管理员权限。 2. 原理 (…

3D点云处理的并行化

在我们的项目中&#xff0c;我们研究了数百万级 3D 点云上的空间局部计算&#xff0c;并提出了两种主要方法&#xff0c;可以提高 GPU 的速度/吞吐量&#xff0c;同时保持最终结果的性能准确性。 通过空间局部&#xff0c;我们的意思是每个像素独立地基于其局部邻域中的点执行…

基于springboot+mybatis+vue的项目实战之(后端+前后端联调)

步骤&#xff1a; 1、项目准备&#xff1a;创建数据库&#xff08;之前已经创建则忽略&#xff09;&#xff0c;以及数据库连接 2、建立项目结构文件夹 3、编写pojo文件 4、编写mapper文件&#xff0c;并测试sql语句是否正确 5、编写service文件 6、编写controller文件 …

标准引领 | 竹云参编《面向云计算的零信任体系》行业标准正式发布!

近日&#xff0c;中华人民共和国工业和信息化部公告2024年第4号文件正式发布行业标准&#xff1a;YD/T 4598.1-2024《面向云计算的零信任体系 第1部分&#xff1a;总体架构》&#xff08;后简称“总体架构”&#xff09;&#xff0c;并于2024年7月1日起正式实施。 该标准汇集大…

vector介绍与使用【C++】

C vector 前言一、vector的介绍c文档介绍简介 二、vector的定义和使用vector的定义vector代码演示 vector的使用vector iterator 的使用vector 空间增长问题vector 增删查改vector 迭代器失效问题引起底层空间改变eraseg与vs检测比较string迭代器失效 vector 在OJ中的使用只出现…

四、 现行数据出境制度下的三条合规路径是什么?如何判断?

综合《网络安全法》《数据安全法》以及《个人信息保护法》这三大数据合规基本法律要求来看&#xff0c;企业开展数据出境活动时&#xff0c;应结合自身的主体类型、出境数据类型和数量&#xff0c;综合判断是否须要额外&#xff08;1&#xff09;申报并通过数据出境安全评估&am…

欧洲央行管委内格尔:通胀压力或将上升,未来利率水平可能保持相对高位

欧洲央行管委约阿希姆内格尔在本周二的一次讲话中表示&#xff0c;欧洲央行可能面临一系列潜在因素导致的通胀压力加大的情况。他指出&#xff0c;人口趋势可能导致持续较高的工资增长&#xff0c;并强调通胀率可能不会回到疫情前的低迷状态。 内格尔指出&#xff0c;考虑到全…

如何看待2024数维杯?

一、赛事介绍 美赛结束后,2024年又一场高含金量数模竞赛开始报名啦!数维杯每年上半年为数维杯国赛(5月,俗称小国赛),下半年为数维杯国际赛(11月),累计参赛高校千余所,参赛人数超14万人,经过八年多的发展,已成为继数学建模国赛和美赛之后的第三大全国性数学建模赛事,…

通义千问免费新功能:EMO,让照片和视频“活”起来

&#x1f9d9;‍♂️ 诸位好&#xff0c;吾乃斜杠君&#xff0c;编程界之翘楚&#xff0c;代码之大师。算法如流水&#xff0c;逻辑如棋局。 &#x1f4dc; 吾之笔记&#xff0c;内含诸般技术之秘诀。吾欲以此笔记&#xff0c;传授编程之道&#xff0c;助汝解技术难题。 &#…

Git克隆仓库报错:HTTP/2 stream 1 was not closed

报错及原因 fatal: unable to access ‘https://github.com/xxx/’: HTTP/2 stream 1 was not closed cleanly before end of the underlying stream http/2 和 http/1.1之间有个区别是“HTTP2 基于 SPDY&#xff0c;专注于性能&#xff0c;最大的一个目标是在用户和网站间只…

国际数字影像产业园专场招聘会暨四川城市职业学院双选会成功举办

为了进一步强化校企合作&#xff0c;链接企业与高素质人才&#xff0c;促进毕业生实现高质量就业&#xff0c;2024年5月7日&#xff0c;“成就梦想 职通未来”国际数字影像产业园专场招聘会暨四川城市职业学院2024届毕业生校园双选会成功举行。 当天&#xff0c;国际数字影像产…

【建网护网三十载】 守护不息创新不止,C3安全AI未来!

30年&#xff0c;中国互联网从起步探索到领先全球。1994年4月20日&#xff0c;中国正式开通首条64K的国际专线&#xff0c;标志着我国成功实现与国际互联网的全功能接轨&#xff0c;展开互联网快速发展的三十载。 回望30年&#xff0c;亲历建网&#xff0c;投身建设&#xff0c…