算法day10

news2024/11/24 20:28:15

算法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 := false
        for i := 1; i < len(runes); i++ {
            if runes[i] == runes[i-1] {
                runes = append(runes[:i-1], runes[i+1:]...)
                judge = true
                break
            }
        }
        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.coloradmin.cn/o/1434003.html

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

相关文章

[Python]MacBook安装pyenv多版本管理

对比之前文章提到过Go的多版本工具[每周一更]-(第54期)&#xff1a;Go的多版本管理工具相应的经验&#xff0c;然后本地将python也配置下多版本切换&#xff0c;有助于项目的灵活切换&#xff1b; 以下展示用MacBook系统做个栗子&#xff1b;其他系统见末尾的参考&#xff1b; …

力扣热门100题刷题笔记 - 10. 正则表达式匹配

力扣热门100题 - 10. 正则表达式匹配 题目链接&#xff1a;10. 正则表达式匹配 题目描述&#xff1a; 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符 * 匹配零个或多个前面的那一个元素 所谓匹配&#xff…

echarts使用之地图(五)

1 基本使用 百度地图 API : 使用百度地图的 api , 它能够在线联网展示地图 , 百度地图需要申请 ak 矢量地图 : 可以离线展示地图 , 需要开发者准备矢量地图数据。本文使用该方式。 json格式的数据如下&#xff1a; 格式参照&#xff1a;GeoJSON <!DOCTYPE html&…

【动态规划】【精度】1883. 准时抵达会议现场的最小跳过休息次数

作者推荐 【动态规划】【状态压缩】【2次选择】【广度搜索】1494. 并行课程 II 本文涉及知识点 动态规划汇总 LeetCode:1883. 准时抵达会议现场的最小跳过休息次数 给你一个整数 hoursBefore &#xff0c;表示你要前往会议所剩下的可用小时数。要想成功抵达会议现场&#…

windows10忘记密码的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

C语言——O/动态内存管理

目录 一、为什么要有动态内存分配 二、malloc 和 free 1、malloc 2、free 三、calloc和realloc 1、calloc 2、realloc 四、常见的动态内存的错误 1、对NULL指针的解引用操作 2、对动态开辟空间的越界访问 3、对非动态开辟内存使用 free 释放 4、使用free释放一块动…

必看!第六版CCF(中国计算机学会)推荐A类国际学术会议!

中国计算机学会 中国计算机学会&#xff08;CCF&#xff09;是全国性、学术性、非营利的学术团体&#xff0c;由从事计算机及相关科学技术领域的个人和单位自愿组成。作为独立社团法人&#xff0c;CCF是中国科学技术协会的成员之一&#xff0c;是全国一级学会&#xff01; CCF的…

JetPack Compose之Button使用指南

Jetpack Compose系列(8) - Button 跟View体系一样&#xff0c;Compose通过Button来显示按钮状态及响应相关事件等。官方表示其默认遵从Material Design设计理念。 OptIn(ExperimentalMaterialApi::class) Composable fun Button(onClick: () -> Unit,modifier: Modifier …

新数据不影响原来的数据

问题描述 新数据修改时&#xff0c;原来的数据也会受影响 const obj1 ref({ name: slx, age: 20 })const obj2 obj1obj2.value.name hhhhconsole.log(obj1, obj1.value)console.log(obj2, obj2.value)解决方法 (仅适用于对象 在这段代码中&#xff0c;obj1 和 obj2 指向同…

深度学习(生成式模型)—— Consistency Models

文章目录 前言预备知识&#xff1a;SDE与ODEMethod实验结果 前言 Diffusion model需要多次推断才能生成最终的图像&#xff0c;这将耗费大量的计算资源。前几篇博客我们已经介绍了加速Diffusion model生成图像速率的DDIM和Stable Diffusion&#xff0c;本节将介绍最近大火的Co…

idea中找到所有的TODO

idea中找到所有的TODO &#xff08;1&#xff09;快捷键 Alt6 &#xff08;2&#xff09;View -> Tool Windows -> TODO

【GameFramework框架】二、GameFramework框架介绍

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录&#xff1a; https://blog.csdn.net/q7…

【MySQL】在 Centos7 环境安装 MySQL -- 详细完整教程

说明&#xff1a; 安装与卸载中&#xff0c;用户全部切换成为 root&#xff0c;一旦安装&#xff0c;普通用户就能使用。 一、卸载内置环境 1、卸载不要的环境 [rootVM-8-5-centos ~]$ ps ajx | grep mariadb # 先检查是否有mariadb存在 13134 14844 14843 13134 pts/0 14843…

ASP.NET Core 预防开放式重定向攻击

写在前面 为预防钓鱼网站的常用套路&#xff0c;在进行 Web 应用程序的开发时&#xff0c;原则上应该将所有由用户提交的数据视为不可信。如果应用程序中包含了基于 URL 内容重定向的功能&#xff0c;需要确保这种类型的重定向操作只能在应用本地完成&#xff0c;或者明确判断…

STM32F407 CAN参数配置 500Kbps

本篇CAN参数适用 芯片型号&#xff1a;STM32F407xx系统时钟&#xff1a;168MHz&#xff0c;CAN挂载总线APB1为42M波 特 率 &#xff1a;500Kpbs引脚使用&#xff1a;TX_PB9&#xff0c;RX_PB8&#xff1b;修改为PA11PA12后&#xff0c;参数不变。 步骤一、打勾开启CAN&#xf…

SpringCloud-搭建Eureka服务模块

在构建分布式微服务体系中&#xff0c;搭建Eureka服务模块是实现服务注册与发现的关键一步。Spring Cloud作为领先的微服务框架&#xff0c;通过Eureka为我们提供了高效的服务治理能力。本文将深入探讨如何使用Spring Cloud&#xff0c;逐步引导读者完成Eureka服务模块的搭建。…

Qt基础-QFrame控件详解

概述 QFrame继承于QWidget,被QLCDNumber、QToolBox、QLabel、QListView等部件继承,是一个拥有矩形框架的基类。 QFrame可以直接创建成一个没有内容的的矩形框架,框架的样式由边框厚度(lineWidth)、框架形状(QFrame::Shape)和阴影样式(QFrame::Shadow)决定,下图是官网给出的…

JAVA毕业设计126—基于Java+Springboot+Vue的二手交易商城管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的二手交易商城管理系统(源代码数据库)126 一、系统介绍 本项目前后端分离&#xff0c;本系统分为管理员、用户两种角色 1、用户&#xff1a; 注册、登录、…

如何有效的开展接口自动化测试(超详细整理)

一、简介 接口自动化测试是指使用自动化测试工具和脚本对软件系统中的接口进行测试的过程。其目的是在软件开发过程中&#xff0c;通过对接口的自动化测试来提高测试效率和测试质量&#xff0c;减少人工测试的工作量和测试成本&#xff0c;并且能够快速发现和修复接口错误&…

事务和连接池配合使用存在的问题

文章目录 前言例子结果源码 前言 今天讨论一个问题&#xff0c;如果全部方法都加上事务&#xff0c;会不会有问题&#xff1f; 前两天看到一个老项目&#xff0c;xml方式的配置&#xff0c;拦截了所有的方法&#xff0c;增加了事务&#xff0c;不能说它的做法有问题&#xff…