学习Java第六十二天——Hot 100-09-438. 找到字符串中所有字母异位词

Leetcode每日一题:438. 找到字符串中所有字母异位词


bym思路1 、排序法:将两个字符串转换为字符数组,排序后比较是否相等。
bym思路2 、哈希表法:使用一个长度为26的数组(假设只包含小写字母)统计每个字母出现的次数,比较两个字符串的统计结果。这里我把每一个子串都遍历出来了,不知道滑动窗口能用在哪里,看了灵神的灵魂拷问"暴力枚举所有子串?时间复杂度是 O(nk),太慢了。"+图解[1](#1),结合绘图和"方法一:定长滑窗"的代码[2](#2),终于理解滑动窗口妙在哪里了。bym妙就妙在切换下一个子串时,暴力遍历仍需要枚举整个字串,而滑动窗口只需移除左指针的元素,添加一个右指针的元素即可

灵神代码节选:

java 复制代码
for (int right = 0; right < s.length(); right++) {
            cntS[s.charAt(right) - 'a']++; // **右端点字母进入窗口**
            int left = right - p.length() + 1;
            if (left < 0) { // 窗口长度不足 p.length()
                continue;
            }
            if (Arrays.equals(cntS, cntP)) { // s' 和 p 的每种字母的出现次数都相同
                ans.add(left); // s' 左端点下标加入答案
            }
            cntS[s.charAt(left) - 'a']--; // **左端点字母离开窗口**
    }

by评论区:思考心路历程可以借鉴

做了四十多道题了,也悟出来了一些东西。

其实很多看起来高大上的解法,比如说这里的双指针,都是从最原始最暴力的解法出发不断进行优化。在这里,不难写出暴力解:遍历所有子串,一一与目标串进行比对。

然后我们有两个优化方向:

第一,剪枝。其实通过排除一些条件,就可以无需遍历所有的子串。比方说,if(s.size() - lo < p.size()) break; 当然,更主要的,如果当前遍历到的字符根本不属于目标串,那包含这个字符的子串都无需再看。

其实滑动窗口和双指针就是基于上述剪枝的思路。设置两个指针lo和hi,如果hi指针推入窗口的元素根本不属于目标串,或者数量已经超过目标串中对应字母的数量(两者本质上其实是一样的),那就让lo指针右移,挤出元素。

第二,找到一个高效的比较当前子串与目标串的算法,看是否是异位词。我是这样做的:通过一个大小为26的int数组来记录目标串中每一个字母出现的次数,用这个数组来动态表示当前的目标串。还需要一个int整数来记录字母的种类数。当int整数值为零,也就说明目标串为空。换言之,当前子串是目标串的异位词。

以上算法,时间复杂度O(n), 0ms通过,空间复杂度O(1)


  1. 1456. 定长子串中元音的最大数目 - 力扣(LeetCode) ↩︎

  2. 438. 找到字符串中所有字母异位词 - 力扣(LeetCode) ↩︎

相关推荐
侠客行03175 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪5 小时前
深入浅出LangChain4J
java·langchain·llm
灰子学技术7 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
老毛肚7 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
阿蒙Amon7 小时前
TypeScript学习-第10章:模块与命名空间
学习·ubuntu·typescript
AI绘画哇哒哒7 小时前
【干货收藏】深度解析AI Agent框架:设计原理+主流选型+项目实操,一站式学习指南
人工智能·学习·ai·程序员·大模型·产品经理·转行
风流倜傥唐伯虎7 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
二十雨辰7 小时前
[python]-AI大模型
开发语言·人工智能·python
Yvonne爱编码7 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚7 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言