Day10补代码随想录 理论基础|232.用栈实现队列|225.用队列实现栈|20.有效的括号|1047.删除字符串中的所有相邻重复项
栈和队列理论基础
抽象认识
- 栈是先进后出(FIFO),队列是先进先出(LIFO)
- 队首(先进))队尾(后进)
- 栈顶(后进)栈底(先进)
- 栈(Stack)
- 只在一端进行进出操作(只在一端进一端出)
- 像个篮球框,取用篮球从一端进出。
-
/进栈 int a[1000];//足够大的栈空间 int top=-1;//栈的初始化,栈顶位置标记 for(i=0;i<10;i++){a[++top]=i;//先对top+1,再录入位置,使用++top为了防止最后一次循环赋值后top依旧进行+1,使得top指向了栈外的空数组。 } /出栈 for(i=0;i<10;i++){ print("%d",a[top--]);}
- 队列(Queue)
- 在两端分别进行进和出的操作(一端进一端出)
- 食堂排队,从后面排队,前面买饭离开。
-
//QQ号,有10个数字的排列,排序为奇数的数字取出排列;排序为偶数的数字放入队尾重新报号,组成QQ号。 int a[100]={1,2,3,4,5,6,7,8,9,0},head,tail; //队头队尾 head=0; tail=10;//标记的是最后一个元素后面的空元素 while(head<tail){printf("%d",a[head]);//奇数离开队伍head++;a[tail]=a[head];//偶数放在队尾tail++;//补长队尾head++;//减少队头}
JAVA中的栈和队列
- 栈(Stack) Stack类位于java.util包中
- 基本操作
- push(E item):将元素压入栈顶。
- pop():移除并返回栈顶的元素。
- peek():查看栈顶的元素,但不移除。
- isEmpty():判断栈是否为空。
- 低层实现:基于一个动态数组(Vector)来实现的,和C++类似,可以通过扩展Vector来管理栈中的元素。
- 基本操作
- 队列(Queue) Queue接口
- 常见的实现类
- LinkedList:提供队列的标准实现
- PriorityQueue:优先队列,根据元素的优先级顺序出队。
- ArrayDeque:基于数组的双端队列。
- 基础操作
- add(E e):将元素添加到队尾
- remove():移除并返回队首的元素
- peek():查看队首的元素,但不移除。
- isEmpty():判断队列是否为空
- 底层实现:默认的队列实现是LinkedList,基于双向链表来实现队列的入队和出队操作。ArrayDeque是基于数组的实现,通常性能更好。
- 常见的实现类
几个问题
- Java中的Stack是容器吗?
- 是,Stack是一个继承自vector类的容器。vector是一个可动态扩展的数组,实现了List接口。Stack类本身是一个容器类,提供了栈(LIFO)操作,由于
Stack
继承自Vector
,所以它本质上也继承了Vector
的所有特性,包括动态调整大小和随机访问等。然而,Stack
主要用来模拟栈的行为,提供了栈特有的操作,但并不暴露所有Vector
提供的操作。
- 是,Stack是一个继承自vector类的容器。vector是一个可动态扩展的数组,实现了List接口。Stack类本身是一个容器类,提供了栈(LIFO)操作,由于
- 我们使用的stack是属于什么?
- JAVA标准库(JDK),位于java.util,
- stack类是继承自Vector的一个类,设计用于支持栈(LIFO)行为。
- JAVA的stack是如何实现的?
- Stack是通过继承Vector类来实现的。Vector是一个动态数组,可以自动扩展它的容量。
- Stack通过push()和pop()方法来操作Vector中的元素,以实现栈的LIFO行为。
- stack提供迭代器来遍历stack空间吗?
- 是的,但不推荐使用。
- Stack提供了iterator()方法来获取一个迭代器,从而遍历栈中的元素、但是不符合栈的设计哲学,因为栈是符合先进后出原则,允许迭代器遍历栈中 元素会破坏这一原则。
- 由于栈的特性,只允许访问栈顶元素,允许迭代的做法违背了栈的设计原则,因此并不推荐使用Stack类,推荐使用Deque(双端队列)或ArrayDeque来代替Stack,这些类支持栈和队列的操作,并且不会提供队元素的遍历行为。
- 在java中,没有缺省容器的概念,栈类和队列类都是固定的,不能更换低层容易,Java中的Stack类的底层实现是固定的。
232.用栈实现队列
题目
https://leetcode.cn/problems/implement-queue-using-stacks/description/
使用栈实现队列的下列操作:
push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。
- 你只能使用标准的栈操作 – 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
- 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
- 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
思路
-
思路
- 用****2个栈(入栈)****来改变出栈顺序
- 入栈要全部放在出栈里,模拟队列的行为(如果出栈是空的)
- 队列是先进先出,栈是先进后出,那么就让数先入栈,再将入栈的数移动到出栈里,开口不变。
- 如果要弹出,看看出栈是否为空,如果为空,把所有元素加倒出栈里。
- 用****2个栈(入栈)****来改变出栈顺序
-
代码思路
- 写清各个接口的返回类型
- 初始化入栈和出栈类,创建入栈和出战的对象。
-
class MyQueue{//声明入栈和出栈Stack<Integer> stackIn;Stack<Integer> stackOut;//Initialize public MyQueue(){stackIn=new Stack<>();stackOut=new Stack<>();}//将一个元素放入队列的尾部public void push(int x){stackIn.push(x);//队列从入栈进入}//从队列首部移除元素public int pop(){//队列中的先进先出,就是取出一个元素并返回它。dumpstackIn();//在出栈放入栈pop出来的数return stackOut.pop();//弹出(移除)再返回值}//返回队列首部的元素public int peek(){dumpstackIn();return stackOut.peek();//返回栈顶,但不移除它。}//返回队列是否为空public boolean empty(){return stackIn.isEmpty()&&stackOut.isEmpty();}private void dumpstackIn(){if(!stackOut.isEmpty()) return;//如果出栈不是空的,那就返回不用执行while(!stackIn.isEmpty()){stackOut.push(stackIn.pop());//放入栈pop出来的数}} }/*** Your MyQueue object will be instantiated and called as such:* MyQueue obj = new MyQueue();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.peek();* boolean param_4 = obj.empty();*/
总结
- 声明入栈和出栈
Stack<Integer>
stackIn;
Stack<Integer>
stackOut; - 创建入栈和出栈的对象,stackIn=new Stack<>();stackOut=new Stack<>();
- return stackOut.peek();//默认返回栈顶,但不移除它
225.用队列实现栈
题目
https://leetcode.cn/problems/implement-stack-using-queues/description/
https://programmercarl.com/0225.%E7%94%A8%E9%98%9F%E5%88%97%E5%AE%9E%E7%8E%B0%E6%A0%88.html
【惯性思维用两个队列来模拟栈,其实只用一个队列就可以模拟栈了】
使用队列实现栈的下列操作:
- push(x) – 元素 x 入栈
- pop() – 移除栈顶元素
- top() – 获取栈顶元素
- empty() – 返回栈是否为空
注意:
- 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
- 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
- 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)
- 【单向队列】
思路
- 我的思路
- 队列是先进先出,我们让它先进后出,改变出口方向,每当队列满了之后,从列尾出去
- Karl思路
- 队列是先进先出的顺序,如果用两个队列,将一个队列移动到另一个队列中时,先进先出的顺序还是没有改变。
- 栈pop的是栈顶元素(后进),队列pop的是队首,我们让栈顶元素(后进)元素pop到栈尾,假设栈有n个元素,每次让栈的栈底元素pop出来,需要将前n-1个元素放入到栈底后面。
- 代码
class MyStack {Queue<Integer> queue;//Queue是个接口public MyStack() {queue=new LinkedList<>();//LinkedList是Queue的一个实现类 }public void push(int x) {queue.add(x);//将元素添加到队尾,相当于栈整体移动到队列了 }public int pop() {rePosition();return queue.poll();//移除并返回栈首元素}public int top() {rePosition();int result=queue.poll();//先移除队首(实际是之前的队尾,即后进)queue.add(result);//后进在栈顶,返回return result;}public boolean empty() {return queue.isEmpty();}//将队列前面的元素加入到队列末尾public void rePosition(){int size=queue.size();size--;//需要将size-1个元素移动到队尾while(size-->0)//在每次循环后,将size-1,只要size>0就继续queue.add(queue.poll());//移除并返回队首元素,知道前size-1个元素全部返回} }/*** Your MyStack object will be instantiated and called as such:* MyStack obj = new MyStack();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.top();* boolean param_4 = obj.empty();*/
总结
- size()和length的使用范围
- size()是方法,length是属性
- size():用于动态大小的集合类;Map的键值对数量
- length:固定长度的数组,字符串
- 注意事项
-
接口和实现类
- Queue
<Integer>
queue;//Queue是个接口 - queue=new LinkedList<>();//LinkedList是Queue的一个实现类
- Queue
-
queue的一些用法
- queue.add(x) 将元素加入队尾
- queue.poll() 移除并返回队首元素
-
top()方法需要多练习,很绕。
-
20.有效的括号
题目
https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 注意空字符串可被认为是有效字符串。
示例 1:
- 输入: “()”
- 输出: true
示例 2:
- 输入: “()[]{}”
- 输出: true
示例 3:
- 输入: “(]”
- 输出: false
示例 4:
- 输入: “([)]”
- 输出: false
示例 5:
- 输入: “{[]}”
- 输出: true
思路
- 我的思路
- 思路很混乱,怎么能在栈和队列中实现这些
- Carl
- 三种不匹配的情况
- 字符串里的左方向的括号多余了,不匹配。
- 括号没有多余,但是括号的类型没有匹配上。
- 右方向的括号多余了,不匹配
- 字符串里的左方向的括号多余了,不匹配。
- 三种不匹配的情况
- 代码思路
- 如果是奇数,一定可以发现不匹配字符。
- for循环
- if 遇到(,在栈中加)
- 提前准备比较匹配
- else if { ,在栈中加}
- elseif [,在栈中加]
- 【情况2,3】elseif 栈空(情况3)||不匹配(情况2) return false;相等情况弹出。
- 【情况1】 遍历到最后一个了,如果不是空栈,return false;
- 代码
class Solution {public boolean isValid(String s) {Deque<Character> deque=new LinkedList<>();//声明并创建实例char ch;for(int i=0;i<s.length();i++){ch=s.charAt(i);//提前匹配if(ch=='('){deque.push(')');}else if(ch=='{'){deque.push('}');}else if(ch=='['){deque.push(']');}else if(deque.isEmpty()||deque.peek()!=ch){ //情况2,3return false;}else{//如果是右括号判断是否和栈顶元素匹配deque.pop();}}return deque.isEmpty();} }
总结
- string要转换为char,才能比较
- 注意,情况2,3先判断栈空【情况3】
1047.删除字符串中的所有相邻重复项
题目
https://programmercarl.com/1047.%E5%88%A0%E9%99%A4%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E7%9B%B8%E9%82%BB%E9%87%8D%E5%A4%8D%E9%A1%B9.html
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
- 输入:“abbaca”
- 输出:“ca”
- 解释:例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。
提示:
- 1 <= S.length <= 20000
- S 仅由小写英文字母组成。
【栈的经典应用,栈喜欢做这种消除的操作,栈帮助记录了遍历数组当前元素的时候,前一个元素是什么】
思路
- 我的思路
- 难点,删除完bb后aa又靠近了。迭代。
- 每遍历一个元素,
-
如果有前一个元素,把他的前一个元素储push在栈中。
- 比较它和前一个元素,如果匹配,就删除字符串里的这个元素和前一个元素,不匹配就pop。
-
else if
- continue.
-
- Carl思路
- 消消乐,
- if 栈是空的||不匹配,那么放入当前元素
- else if 消除 pop弹出
- 最后要把栈中的字符串翻转过来
- 消消乐,
- 代码
class Solution {public String removeDuplicates(String s) {ArrayDeque<Character> deque=new ArrayDeque<>();char ch;for(int i=0;i<s.length();i++){ch=s.charAt(i);//如果栈空或不匹配栈顶if(deque.isEmpty()||deque.peek()!=ch){deque.push(ch);}else{//匹配就删掉deque.pop();}}String str="";//剩余的元素while(!deque.isEmpty()){//全pop出去str=deque.pop()+str;//先pop出去的放在前面,恢复正序}return str;} }
总结
-
ArrayDeque 是JAVA中的双端队列数据结构,既可以用作栈,也可以用做队列
- 栈
- push()
- pop()
- 队列
- add()
- poll()
//ArrayDeque会比LinkedList在除了删除元素这一点外会快一点//参考:https://stackoverflow.com/questions/6163166/why-is-arraydeque-better-than-linkedlist
- 栈
-
低级错误,ch=s.charAt(i); 里面是string s 的第i个,而不是直接ch=s.charAt(s);
相关文章:

Day10补代码随想录 理论基础|232.用栈实现队列|225.用队列实现栈|20.有效的括号|1047.删除字符串中的所有相邻重复项
栈和队列理论基础 抽象认识 栈是先进后出(FIFO),队列是先进先出(LIFO) 队首(先进))队尾(后进)栈顶(后进)栈底(先进) 栈(Stack) 只在一端进行进出操作(只在一端进一端出)像个篮球框,取用篮球从一端进出。 /进栈 int a[1000];//足够大的栈空间 int top-1…...

【Devops】什么是Devops?(Development+Operations)和运维的区别?
DevOps(Development Operations)是一种将开发(Development)和运维(Operations)团队结合在一起的文化和实践,目的是通过自动化、协作和持续反馈来加快软件的开发、部署和运维的周期,…...

基于NodeMCU的物联网电灯控制系统设计
最终效果 基于NodeMCU的物联网电灯控制系统设计 小程序关灯 上图展现了小程序关灯过程的数据传输过程:用户下达关灯指令→小程序下发关灯指令→MQTT服务器接收关灯指令→下位机接收与处理关灯指令。 项目介绍 该项目是“物联网实验室监测控制系统设计(…...

Linux驱动开发 IIC I2C驱动 编写APP访问EEPROM AT24C02
在嵌入式开发中,I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,广泛应用于与外设(如 EEPROM、传感器、显示屏等)进行数据交换。AT24C02 是一种常见的 I2C EEPROM 存储器,它提供 2Kbit…...

Linux应用软件编程-多任务处理(线程)
线程:轻量级的进程,线程的栈区独立(8M),与同一进程中的其他线程共用进程的堆区,数据区,文本区。 进程是操作系统资源分配的最小单位;线程是cpu任务调度的最小单位。 1. 线程的创建…...

VITUREMEIG | AR眼镜 算力增程
根据IDC发布的《2024年第三季度美国AR/VR市场报告》显示,美国市场AR/VR总出货量增长10.3%。其中,成立于2021年的VITURE增长速度令人惊艳,同比暴涨452.6%,成为历史上增长最快的AR/VR品牌。并在美国AR领域占据了超过50%的市场份额&a…...

Jenkins管理多版本python环境
场景:项目有用到python3.8和3.9,python环境直接安装在jenkins容器内。 1、进入jenkins容器 docker exec -it jenkins /bin/bash 2、安装前置编译环境 # 提前安装,以便接下来的配置操作 apt-get -y install gcc automake autoconf libtool ma…...
Flutter富文本实现学习
Flutter 代码如何实现一个带有富文本显示和交互的页面。 前置知识点学习 RealRichText RealRichText 和 ImageSpan 不是 Flutter 框架中内置的组件,而是自定义的组件或来自第三方库。这些组件的实现可以提供比标准 RichText 更丰富的功能,比如在富文本…...
如何解决 OpenAI API 连接问题:降级 urllib3 版本
如何解决 OpenAI API 连接问题:降级 urllib3 版本 在使用 OpenAI API 时,很多开发者可能会遇到连接问题,特别是在使用 Python 代码与 OpenAI 进行交互时。常见的错误包括 ProxyError、SSLError 和 MaxRetryError,它们通常表示在通…...
【C语言】库函数常见的陷阱与缺陷(三):内存分配函数[4]--free
C语言中的free函数用于释放之前通过malloc、calloc或realloc动态分配的内存。然而,在使用free函数时,开发者可能会遇到一些陷阱和缺陷。 一、功能与用法 free 函数是 C 语言中用于释放动态分配内存的关键函数。在程序使用 malloc、calloc 或 realloc 等函数在堆上分配了内存…...

论文分享 | PromptFuzz:用于模糊测试驱动程序生成的提示模糊测试
大语言模型拥有的强大能力可以用来辅助多种工作,但如何有效的辅助仍然需要人的精巧设计。分享一篇发表于2024年CCS会议的论文PromptFuzz,它利用模型提示生成模糊测试驱动代码,并将代码片段嵌入到LLVM框架中执行模糊测试。 论文摘要 制作高质…...

AWS K8s 部署架构
Amazon Web Services(AWS)提供了一种简化的Kubernetes(K8s)部署架构,使得在云环境中管理和扩展容器化应用变得更加容易。这个架构的核心是AWS EKS(Elastic Kubernetes Service),它是…...

JavaSE笔记(四)
Java泛型与集合类 在前面我们学习了最重要的类和对象,了解了面向对象编程的思想,注意,非常重要,面向对象是必须要深入理解和掌握的内容,不能草草结束。在本章节,我们会继续深入了解,从我们的泛型开始,再到我们的数据结构,最后再开始我们的集合类学习。 走进泛型 为…...

C语言基础——指针(5)
一. 函数指针变量 1. 函数指针变量的定义: 类比数组指针变量,数组指针变量是存放数组地址的变量,那么同理,函数指针变量就是存放函数地址的变量。 2. 创建函数指针变量: 函数是有地址的࿰…...

curl+openssl 踩坑笔记
curl编译:点击跳转 踩坑一 * SSL certificate problem: unable to get local issuer certificate * closing connection #0 curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.se/docs/sslcerts.html …...

Unity 实现Canvas显示3D物体
新建一个UI相机,选择渲染层为UI 将主相机的渲染层去掉UI层 、 将Canvas的RenderMode设置为Screen Space - Camera,将RenderCamera设置为UI相机 新建3D物体的UI父物体,并将3D物体的层级设置为UI层 适当的放缩3DObjParent,让3D物体能显示出来…...
【Docker命令】如何使用`docker exec`在容器内执行命令
大家好,今天我们来聊聊Docker容器管理中的一个非常有用的命令:docker exec。在日常工作中,我们经常需要在运行中的Docker容器内执行各种命令,docker exec正是帮助我们实现这一需求的利器。下面我将通过一个简单的例子,…...

NetSuite Formula(HTML)超链打开Transaction
当Saved Search作为Sublist应用在Form时,如果Document Number是Group过的,则会出现如下超链失效的情况。 解决办法: 可以利用Saved Search中的Formula(HTML)功能来构建超链,用于打开Transaction。 以下图…...

【React】- 跨域PDF预览、下载(改文件名)、打印
我们经常会碰到跨域来方位PDF,同时需要下载、打印的需求,通常由于浏览器的安全策略,可以预览,但是下载和打印可能会受限,这时候怎么办呢? 1.创建一个隐藏的标签 要下载 iframe 中的 PDF 文件,…...
git clone ssh 设置代理
Linux配置方法 编辑 ~/.ssh/config 文件 Host github.com Hostname github.com ProxyCommand nc -v -x 127.0.0.1:1080 %h %pwindows配置方法 编辑 C:\Users\当前用户名.ssh\config 文件 Host github.com Hostname github.com ProxyCommand connect -S 127.0.0.1:1080 %h %…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...