当前位置:网站首页>LeetCode第三题(Longest Substring Without Repeating Characters)三部曲之三:两次优化
LeetCode第三题(Longest Substring Without Repeating Characters)三部曲之三:两次优化
2022-08-04 00:32:00 【51CTO】
欢迎访问我的GitHub
这里分类和汇总了欣宸的全部原创(含配套源码): https://github.com/zq2599/blog_demos
- 本文是《LeetCode第三题(Longest Substring Without Repeating Characters)三部曲》的第三篇,之前的两篇文章列出了思路并写出了Java代码,虽然在LeetCode网站提交通过,但是成绩并不理想,40多毫秒的速度,与诸多优秀的方案有不小差距,
今天就来一起优化代码,提升速度;
原有代码
- 这里再回顾一下原有代码:
第一次优化
这次的重点是HashSet对象,此对象保存窗口中的所有元素,每加入一个新元素之前都检查HashSet中是否存在该元素;
如下图所示,代码中通过set.add和set.remove方法将HashSet中的内容始终与窗口中的内容保持一致:
优化前:判断一个元素是否在窗口中,现在的做法是以HashSet中为准,当判定某个元素要从窗口中移除,就调用HashSet的remove方法从HashSet中删除;
上述的代码可以优化,优化后可以不用执行HashSet的remove方法,具体的逻辑是使用HashMap替代HashSet,HashMap的key是字符串的元素,value是元素在数组中的位置,举个例子,当left=1,right=3时,整体的效果是下图这样的,HashMap中已经保存了"a"、“b”、"c"三个元素作为key,而value就是它们在数组中的下标:
现在要检查数组中下标为4的元素"b":以"b"为key查找HashMap,如果不存在就表示不在窗口中,如果存在,就用对应的value=1去和left比较,如果小于left就表示不在窗口中,如果大于或者等于left就表示在窗口中,如下图所示:
- 这里要注意的是:hashmap中任意一个value,表示的是某个元素在整个数组中的位置,而不是在窗口中的位置,因为程序中不会对hashmap做remove操作;
- 接着上面的图分析,"b"元素被发现在窗口中存在后,除了将left调整为2,right调整为4,还要调用HashMap的put方法,将"b"元素的位置从原来的1更新为4;
- 另外还有个优化点:假设当前窗口中是"abc",而检查的元素是"b",之前的代码中,要执行两次循环:先删除"a",left加一,再删除"b",left再加一,现在用了HashMap就能得到"b"的位置,直接将left改为"b"的下一个位置即可,不需要执行两次循环了;
- 以上就是优化思路了,用HashMap取代HashSet,不再执行remove方法,对代码的调整并不大,调整后的完整代码如下:
提交上述代码到LeetCode,这次的成绩是27毫秒,比之前好了不少,如下图:
然而,这个成绩依然很平庸,因为它还有可优化之处,接下来再次优化;
第二次优化
第一次的优化点是消除remove方法和while循环次数,第二次优化则是针对HashMap,每次处理新的元素都涉及到HashMap的操作,如果您对HashMap的内容有所了解,就知道计算hashcode、创建EntrySet,调用equals方法这些操作会被频繁执行,如果能省去这些操作,那么性能应该会有明显提升,问题是:如何才能去掉HashMap而不影响功能呢?
我们先明确HashMap在程序中的作用:保存一个元素在数组中的位置,所以优化的方向就是寻找HashMap的替代品;
假设一共可能出现二十六种字符:从"a"到"z",那就简单了,用一个长度为26的int数组来记录每个字符的位置,array[0]的值就是元素"a"的位置,array[1]的值就是元素"b"的位置,array[2]的值就是元素"c"的位置,如下图所示,图中的数字97是"a"的ASCII码:
按照上面的设计,array[0]=3就表示"a"元素在整个数组中最后一次出现的位置是3,array[1]=1表示"b"元素在整个数组中最后一次出现的位置是1,array[2]=2就表示"c"元素在整个数组中最后一次出现的位置是2,如下图:
按照以上设计是不是就可以立即编码并提交到LeetCode了呢?我当时就是这么做的,很不幸因为测试没有通过而提交失败了,没通过的原因是:字符串中不仅会有"a"到"z"的小写,还有大写字母、空格字符、加减乘除等字符,遇到这些字符时,我们之前设计的长度26的数组就不够用了,看来要重新设计数组;
新的数组总长度是95,这是因为所有英文可见字符一共是95个,从空格开始,到"`"结束,如下图的三个红框所示:
如上所示,长度为95的数组,可以将所有可见字符都纳入进来,array[0]保存的是空格字符的位置,因此计算字符"a"在array数组中的下标就从之前的**‘a’-97=0变成了’a’-32=65**;
另外要注意的是,这个数组中每个元素初始值都是**-1**,表示字符串中没有这个元素(或者说还没有处理到);
按照上述思路优化后的代码如下所示,可见改动并不大,只是把HashMap相关的地方全部改成了上述的数组逻辑:
将以上代码提交到LeetCode,顺利通过,成绩提升到17ms,超过了99.94%的java方案,如下图:
最终效果证明这次优化的方向和结果都是正确的,之前已经有朋友问过优化思路从何而来,其实灵感来自桶排序,思想是类似的;
至此,LeetCode第三题的解题思路、编码实现、优化实战就全部完成了,希望能给读者您在解题过程中带来一些参考,刷题之路,大家一起努力!
欢迎关注51CTO博客:程序员欣宸
边栏推荐
- 114. 如何通过单步调试的方式找到引起 Fiori Launchpad 路由错误的原因
- SQL优化的一些建议,希望可以帮到和我一样被SQL折磨的你
- 虚拟机CentOS7中无图形界面安装Oracle
- js函数防抖和函数节流及其使用场景
- [Miscellaneous] How to install the specified font into the computer and then use the font in the Office software?
- C语言实验十五 文件
- typescript51-泛型的基本使用
- c语言分层理解(c语言操作符)
- 2023年第六届亚太应用数学与统计学国际会议(AMS 2023)
- 求解同余方程 数论 扩展欧几里得
猜你喜欢
带你造轮子,自定义一个随意拖拽可吸边的悬浮View组件
Web3 security risks daunting?How should we respond?
POE交换机全方位解读(下)
Apple told Qualcomm: I bought a new campus for $445 million and may plan to speed up self-development of baseband chips
LeetCode 19:删除链表的倒数第 N 个结点
ML18-自然语言处理
电子制造企业部署WMS仓储管理系统的好处是什么
一文参透分布式存储系统Ceph的架构设计、集群搭建(手把手)
114. 如何通过单步调试的方式找到引起 Fiori Launchpad 路由错误的原因
Install third-party packages via whl
随机推荐
机器学习——库
typescript53 - generic constraints
.NET静态代码织入——肉夹馍(Rougamo) 发布1.1.0
七夕活动浪漫上线,别让网络拖慢和小姐姐的开黑时间
FastDFS 一文读懂
高斯推断推导
分子个数 数论(欧拉函数 前缀和
孙宇晨受邀参加36氪元宇宙峰会并发表主题演讲
2022年8月份DAMA-CDGA/CDGP数据治理认证招生简章
The problem of disorganized data output by mnn model
pcl点云数据 转化为 Eigen::Map
Getting started with MATLAB 3D drawing command plot3
数据库扩容也可以如此丝滑,MySQL千亿级数据生产环境扩容实战
js函数防抖和函数节流及其使用场景
面试必问的HashCode技术内幕
求解同余方程 数论 扩展欧几里得
Vant3—— 点击对应的name名称跳转到下一页对应的tab栏的name的位置
typescript48-函数之间的类型兼容性
【杂项】如何将指定字体装入电脑然后能在Office软件里使用该字体?
Analysis: What makes the Nomad Bridge hack unique