算法day10

算法day10

  • 20 有效的括号
  • 1047 删除字符串中的所有相邻重复性
  • 150 逆波兰表达式求值

20 有效的括号

拿到这个题的想法,首先我在想我能不能用数组的操作来扫描做。后来想想,如果这样做那特判也太多了,不好做。然后第二个想法就是用栈来做,我之前看过有类似的算法题,但是具体细节怎样我忘了。这里我就之间看题解学习了。

看完解题我回来了:

括号匹配时使用栈解决的经典问题,题意要求:就是和我们平时写代码的顺序一样,有左括号,相应的位置必须要有右括号。

由于栈结构的特殊性,非常适合左对称匹配类型的题目
做这个题之前,首先要弄清楚,字符串括号不匹配有几种情况。
看几个不匹配的例子:
1.这个显然左边第一个多了
请添加图片描述
2.这个显然里面这两个对不上请添加图片描述
3.这个就是多余了。请添加图片描述

现在来看这个题的思路是怎样的
我个人看这个图的适合感觉这个是最好理解的:请添加图片描述
这个图体现了怎样的算法思路:
首先我先创建一个空栈。
是左括号,那就之间入栈,如果是右括号那就要进行弹栈,但是这个弹栈操作要注意。

接下来细说弹栈操作:从这个图我们可以发现一件事,你遇见的第一个右括号比如这个括号我记为},然后可以发现这个栈顶元素,它必须是这个}相应的{,如果不是或者栈中已经没有左括号了,那就说明字符串s直接无效,并返回False,为了快速判断括号的类型,我们可以使用哈希表存储每一种括号。哈希表的键为右括号,值为相同类型的左括号。

在遍历结束后,如果栈中啥也没有,则可以返回true了,否则返回False。

还可以有一个小优化
如果字符串的长度为奇数可以直接返回false,节省计算的次数。

下面来看代码怎么写的

正确代码

func isValid(s string) bool {hash := map[byte]byte{')':'(', ']':'[', '}':'{'}stack := make([]byte, 0)if s == "" {return true}for i := 0; i < len(s); i++ {if s[i] == '(' || s[i] == '[' || s[i] == '{' {stack = append(stack, s[i])} else if len(stack) > 0 && stack[len(stack)-1] == hash[s[i]] {stack = stack[:len(stack)-1]} else {return false}}return len(stack) == 0
}

这个代码逻辑可以说和我上面解释的一模一样。别去看官方题解那个代码,写的太花里胡哨了。

总结:
1.需要一个map,来存右括号的映射(如果你不用映射,你就要写一堆的if判断,所以这里放心用map,而且空间复杂度的大头根本就不是这个map,这个map可以说是常数级的空间,空间复杂度主要取决于这个栈,这个栈的空间复杂度达到了o(n)).
2.需要一个栈进行消除。

思考
(1).我今天看到这个题解又有了一点go语言语法积累:
以前我一直认为在go语言中,string类型的字符串 ,对下标的操作是不行的。然后我在这个题解中发现是可以的。
这里进行改正:
在go语言中,确实可以通过下标访问字符串的单个字符。但它获取的实质并不是字符,这样做实际上是访问字符串中相应位置的字节,而不是字符。因为Go中字符串是按字节组织的,并且默认使用UTF-8编码。
当我使用下标访问字符串,比如s[i],我得到的是字符串在i位置上的字节,如果字符串包含多字节的UTF-8字符,单个字节可能不代表完整字符。
这里举个例子:
1.s:=“hello”

fmt.Println(s[0]) // 输出 104, 即 'h' 的 ASCII 码
fmt.Println(s[1]) // 输出 101, 即 'e' 的 ASCII 码

如果我真想把h输出,那就要格式化输出:

s := "hello"
fmt.Printf("%c\n", s[0]) // 将输出字符 'h'
s := "你好"
fmt.Println(s[0]) // 不会输出 '你' 或 '好',而是输出一个字节的值

因为汉字是三字节,这里会输出 你 这个汉字的第一个字节,这个汉字的字节多半都是大于127的。

(2)我的map的初始化写的也不是很好,这部分的语法就在这里补起来
hash := map[byte]byte{‘)’:‘(’, ‘]’:‘[’, ‘}’:‘{’}
这个初始化我当时忘了,我真是服了。
就直接写好map了后面{},直接写键值对,然后用逗号进行分割就行。

(3)我写的时候还犯了一个有关数据错误,因为我在操作有关字符的时候都喜欢用rune这个数据类型,但是我在访问s[i]的时候出现了数据不匹配的情况,这里主要是我对rune和byte没有清楚的认识:
在go语言中rune是int32的别名,byte是uint8的别名。这里在访问字符s[i]的时候要小心,因为字符串是字节组织的。


1047删除字符串中的所有相邻重复性

这题我上来想的还是暴力:
字符串先转切片,设置一个bool遍历judge判断是否删干净,然后遍历切片检查是否有重复相邻,有就用切片操作删除这两个切片元素。删干净了judge=true,然后返回结果。

这个解法是可以过的,但是时间复杂度太高了,是o(n^2)
暴力解

func removeDuplicates(s string) string {runes := []rune(s)for {judge := falsefor i := 1; i < len(runes); i++ {if runes[i] == runes[i-1] {runes = append(runes[:i-1], runes[i+1:]...)judge = truebreak}}if !judge {break}}return string(runes)
}

不建议用暴力

正解:用栈
这种解法其实也是括号匹配这一类的题目。上个题目是相邻的括号,左括号的右括号匹配上了,进行删除,那这个题目就是相邻的字母如果相同就做一个消除的操作。这种消除规则的题,用栈都很合适。

来看这个题的模拟,看完你就知道为啥用栈了请添加图片描述
我这里立马就可以总结了,扫描s的时候看和栈顶是否相等,相等就弹栈,不相等就入栈,最后遍历完了就把栈逆序输出就是结果。

func removeDuplicates(s string) string {stack := []byte{}for i:=0;i<len(s);i++{if len(stack)>0 && stack[len(stack)-1]==s[i]{stack=stack[:len(stack)-1]}else{stack=append(stack, s[i])}}return string(stack)
}

用go语言写就是有个好处,由于我是用数组模拟的,所以就没必要stack翻转输出结果了。


逆波兰表达式求值

知识补充:
逆波兰式是什么:就是后缀表达式。
波兰式是什么:前缀表达式。

前缀表达式,中缀表达式,后缀表达式是什么?
中缀表达式:就是我们平时习惯写的计算式a+b-c这种就叫中缀表达式,中缀表达式是我们比较习惯的计算方式,但是对于计算机来说,中缀表达式并不方便计算。对于计算机来说计算前缀表达式或后缀表达式的值就非常的简单。

前缀表达式:即表达式的运算符位于两个相应的操作数之前。
后缀表达式:即表达式的运算符位于两个相应的操作数之后。

因为我们编程是用计算机来计算。那么就会涉及将中缀表达式转后缀表达式,中缀表达式转前缀表达式。然后再使用对应的表达式的计算方法来计算结果。

中缀转后缀
我建议看这个视频,很清楚。只有一分钟。
https://www.bilibili.com/video/BV1xp4y1r7rc/?spm_id_from=333.337.search-card.all.click&vd_source=49ceaf0b94868131c32ccefb11e30e8f
要点我总结一下:
1.准备一个栈作为辅助,这个栈中只装操作符。
2.数字直接加入后缀表达式。
3.操作符入栈有优先级这个说法,这里我们分栈内字符和栈外字符。
(1)不管栈内或栈外,就是*/比±优先级高,栈外优先级比栈顶元素高就直接入栈。如果栈外操作符优先级比栈内低,那么栈内会一次进行比较然后出栈,直到能让栈外操作符入栈。
(2)(和)这个比较特殊:(直接入,比都不用比。栈外遇到),那么栈就必须进行弹栈,直到弹出(才停下来。注意这个配对的’)'不会进栈。
4.扫描完字符串了再把栈中的元素一次弹出加入后缀表达式

中缀转后缀还有个方法,就是将中缀表达式写成数的形式,然后后续遍历,就得到了后缀表达式。

中缀转前缀
1.初始化一个栈,拿来存运算符
2.对这个表达式从右往左扫描
3…遇到数字直接加入前缀表达式
4.遇到操作符:
(1)遇到’)‘直接入栈,遇到’(‘则开始进行弹栈,直到’)‘弹出为止,注意’(‘不入栈。
(2)遇到运算符,优先级的说法和上面中缀转后缀一样。栈内’)'优先级最低。
5…扫描完字符串了再把栈中的元素一次弹出加入前缀表达式

这里就来看后缀表达式求值,也就是逆波兰表达式求值。

看题解时的一点感悟:我们平时的中缀计算,我们要考虑括号的优先级。但是在后缀表达式计算中可以发现,居然没有括号。而且我们中缀转后缀的适合也是不把括号加入表达式,这样影响计算吗?回答是不会,因为计算机的计算就是顺序的扫描后缀表达式,它是顺序扫描,根本就不用管括号优先级。那么计算机如何顺序处理这个后缀表达式字符串,答案是用的栈。

这个题栈思路的体现就是遇到操作符,就做栈顶两个元素的合并操作。三个元素,两个操作数,一个操作符做一个计算然后再把计算结果加入栈中。非常适合做相邻字符的消除操作。

这里直接看后缀表达式计算思路:
扫描字符串,遇到数字直接加入栈中,遇到操作符,弹出栈顶两个元素,进行计算之后再压入栈中,直到扫描完毕,此时栈中剩下的那个元素就是计算结果。


import "strconv"
func evalRPN(tokens []string) int {stack:=[]int{}for _,v := range tokens{val,err:=strconv.Atoi(v)if err==nil{stack = append(stack,val)}else{num1,num2:=stack[len(stack)-2],stack[len(stack)-1]stack=stack[:len(stack)-2]if v == "+"{stack=append(stack,num1+num2)}else if v == "-"{stack=append(stack,num1-num2)}else if v == "*"{stack=append(stack,num1*num2)}else if v == "/"{stack=append(stack,num1/num2)}}}return stack[0]
}

这个代码写下来我还是出了一些语法上的错误,这里需要积累。

1.第一个问题是类型匹配的问题。v == “+”,我之前写的是v == ‘+’,我之前写的这个会报类型不匹配。后来我发现我的问题出在了哪里,func evalRPN(tokens []string) int,这个地方传的参数是字符串切片我真是服了。所以我for range得到的元素,那类型肯定是string,我当时以为是直接给了个字符串。所以这里用双引号就是"+"就是字符串类型。如果这个题给的字符串那么写’+'是没毛病的。

2.做的时候的一个问题,我怎么将字符转化成对应的整数。给的参数全是字符串,这里用的 strconv.Atoi(v)这个函数,这里必须要进行掌握。

strconv.Atoi 函数的转换原理主要基于解析和转换字符串中的数字字符。它从字符串的开始逐个字符地解析,将字符数字(如 ‘3’)转换为其对应的整数值(如 3),并构建出最终的整数值。

例如,对于字符串 “123”,strconv.Atoi 会这样处理:

解析 ‘1’,识别为整数 1。
解析 ‘2’,将当前整数乘以 10(变为 10)并加上 2,得到 12。
解析 ‘3’,再次乘以 10(变为 120)并加上 3,得到 123。
这个过程涉及将每个字符表示的数字从 ASCII 编码转换为其数值,并通过数学运算构造最终的整数结果。如果字符串中包含非数字字符或格式不正确,strconv.Atoi 将返回错误。

原理:ASCII 到数值的转换:对于字符串中的每个字符,strconv.Atoi 会将其从 ASCII 码转换为相应的数值。例如,字符 ‘0’ 到 ‘9’ 在 ASCII 表中对应的值是 48 到 57。要将这些字符转换为相应的整数 0 到 9,可以将字符的 ASCII 值减去 48。比如,ASCII 码为 51 的字符 ‘3’ 转换为整数 3 是通过计算 51 - 48 得到的。

数值构建:然后,strconv.Atoi 从字符串的左侧开始,逐个字符地计算整数值。对于每个新的数字字符,先将当前的数值乘以 10(向左移动一个数位),然后加上新字符代表的数值。例如,解析 “123” 时,开始是 1,然后是 1 * 10 + 2(得到 12),最后是 12 * 10 + 3(得到 123)。

了解完这个就感觉好做多了。注意它的参数很重要,一定要是string类型的。

3.一个衍生问题,单个字符’1’它的值应该是ASCII值,怎么转成我要的int值1.
要这么转化

char := '1'
num := char - '0'  // num 的类型是 int32 (rune),值是 1

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

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

相关文章

机器学习-基础分类算法-KNN详解

KNN-k近邻算法 k-Nearest Neighbors 思想极度简单应用数学只是少效果好可以解释机器学习算法使用过程中的很多细节问题更完整的刻画机器学习应用的流程 创建简单测试用例 import numpy as np import matplotlib.pyplot as plt raw_data_X [[3.393533211, 2.331273381],[3.1…

ubuntu20.04安装sumo

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 有问题&#xff0c;请大家指出&#xff0c;争取使方法更完善。这只是ubuntu安装sumo的一种方法。一、注意事项1、首先明确你的ubuntu的用户名是什么 二、sumo安装1.…

基于springboot篮球论坛系统源码和论文

首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。本项…

国家博物馆逆向抢票协议

逆向工程的具体步骤可以因项目和目标系统的不同而有所变化。然而&#xff0c;以下是一般逆向工程的一般步骤&#xff1a; 1. 分析目标系统&#xff1a;对待逆向的系统进行调研和了解&#xff0c;包括其架构、功能、使用的技术等方面的信息。 2. 反汇编或反编译&#xff1a;使…

保姆级CDN使用教程,解决可能出现的各种问题

如果你还没有注册雨云&#xff08;rainyun&#xff09;&#xff0c;可以通过该链接进行注册雨云 - 新一代云服务提供商 通过该链接注册是可以白嫖到优惠券的&#xff0c;可以白嫖CDN。 比直接注册划算。 雨云的cdn在国内表现是非常不错的&#xff0c;而且不需要域名进行备案 在…

如何创建长期有效的文件二维码?支持多文件批量生成单独二维码

现在很多人为了避免文件通过文件有时效的问题&#xff0c;会将文件生成二维码之后来使用&#xff0c;将文件存入二维码中通过扫码调取云端的储存的数据来实现文件的预览或者下载。那么对于想要学习文件二维码制作的小伙伴&#xff0c;可以学习下面的方法来制作&#xff0c;利用…

flask基于django大数据的证券股票分析系统python可视化大屏

证券分析系统采用B/S架构&#xff0c;数据库是MySQL。网站的搭建与开发采用了先进的Python进行编写&#xff0c;使用了Django框架。该系统从两个对象&#xff1a;由管理员和用户来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对股票信息、股票买入、…

XML传参方式

export function groupLoginAPI(xmlData) {return http.post(/tis/group/1.0/login, xmlData, {headers: {Content-Type: application/xml,X-Requested-With: AAServer/4.0,}}) }import {groupLoginAPI} from "../api/user"; function (e) { //xml格式传参let groupX…

网络安全全栈培训笔记(60-服务攻防-中间件安全CVE复现WeblogicJenkinsGlassFish)

第60天 服务攻防-中间件安全&CVE复现&Weblogic&Jenkins&GlassFish 知识点: 中间件及框架列表: lIS,Apache,Nginx,Tomcat,Docker,Weblogic,JBoos,WebSphere,Jenkins, GlassFish,Jira,Struts2,Laravel,Solr,Shiro,Thinkphp,Sprng,Flask,jQuery 1、中间件-Web…

【C/C++ 10】扫雷小游戏

一、题目 写一个扫雷小游戏&#xff0c;每次输入一个坐标&#xff0c;若该处是地雷&#xff0c;则游戏失败&#xff0c;若该处不是地雷&#xff0c;则显示周围地雷数量&#xff0c;若扫除全部非地雷区域&#xff0c;则扫雷成功。 二、算法 设置两张地图&#xff08;二维数组&…

chisel decoupled

Decoupled 即为接口包装一层valid 和 ready &#xff0c;decoupled 默认方向为输出&#xff0c;如果需要输入&#xff0c;可以加.flip, Decoupled 可以直接调用Bundle或者Bits&#xff0c;Bundle 内的端口也应该用bits定义 注意: ready和valid不能组合耦合&#xff0c;否则可能…

C# SSH.NET 长命令及时返回

在SSH中执行长时间的命令&#xff0c;SSH.NET及时在文本框中返回连续显示结果。 c# - Execute long time command in SSH.NET and display the results continuously in TextBox - Stack Overflow 博主管理了一个服务器集群&#xff0c;准备上自动巡检工具&#xff0c;测试在…

Linux Rootkit实验|01 基于修改系统调用表的Hook

Linux Rootkit实验&#xff5c;01 基于修改系统调用表的Hook 文章目录 Linux Rootkit实验&#xff5c;01 基于修改系统调用表的Hook实验说明实验环境实验过程一 基于修改sys_call_table的系统调用挂钩1 寻找sys_call_table内存地址2 关掉写保护3 修改sys_call_table 二 基于系统…

AI新工具(20240203) 文心一言APP数字分身;HuggingChat Assistants等

文心一言APP数字分身-一键生成专属数字分身 文心一言数字分身是一项新功能&#xff0c;用户只需一张照片和录制三句语音&#xff0c;就能创建一个专属的数字分身。这个数字分身还支持个性化定义名称、声音、MBTI性格等&#xff0c;用户可以选择是否公开自己的数字分身。这个功…

概率论中的全概率公式、贝叶斯公式解析

全概率公式 定义 全概率公式是用来计算一个事件的概率&#xff0c;这个事件可以通过几个互斥事件的并集来表示。这几个互斥事件称为“完备事件系”。实质是由原因推结果。 公式 用途 全概率公式通常用于计算一个事件的总概率&#xff0c;特别是当这个事件与几个不同的因素相关…

C++进阶--C++11 lambda表达式

C进阶--C11 lambda表达式 一、lambda表达式的概念二、lambda表达式的语法2.1 lambda表达式语法格式2.2 lambda表达式捕获列表说明 三、lambda表达式交换两个数3.1 标准写法3.2 利用捕捉列表进行捕捉3.3 利用捕捉列表进行捕捉 四、lambda表达式的底层原理4.1 底层原理4.2 lambda…

qt中使用mysql 数据库

QT 版本介绍 虽然版本是这个&#xff0c;但是工作目录确是&#xff1a; 下面陈述安装步骤 第一步&#xff1a; 就是安装MYSQL 数据库&#xff0c;在此不再赘述了&#xff0c;很多博主已经上传了。 第二步&#xff1a; 就是拷贝QT 对应mysql 的版本驱动到 QT 的编译器文件中…

【gulp+jq+html】添加环境变量,并在js中使用(判断环境,更改api接口域名)+ 附gulpfile.js代码

参考博文&#xff1a; gulp分离环境 gulp中如何配置环境变量 gulp环境变量配置 1、安装cross-env插件 npm install cross-env -d2、package.json更改scripts "scripts": {"clean": "gulp clean","serve:test": "cross-env NODE…

IDEA JDBC配置

一、在pom中添加依赖 <dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency></dependencies> 然后同步一下 二、编写代码…

C++项目-- 高并发内存池(一)

C项目-- 高并发内存池&#xff08;一&#xff09; 文章目录 C项目-- 高并发内存池&#xff08;一&#xff09;一、项目介绍1.项目来源2.内存池介绍1.池化技术2.内存池3.内存池主要解决的问题4.malloc 二、定长内存池1.定长内存池的设计2.代码实现3.性能测试4.直接在堆上申请空间…