学习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) ↩︎

相关推荐
Derek_Smart43 分钟前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP2 小时前
MyBatis-mybatis入门与增删改查
java
孟陬5 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌5 小时前
一站式了解四种限流算法
java·后端·go
华仔啊5 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
也些宝6 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java
Nyarlathotep01137 小时前
SpringBoot Starter的用法以及原理
java·spring boot
wuwen57 小时前
WebFlux + Lettuce Reactive 中 SkyWalking 链路上下文丢失的修复实践
java
SimonKing7 小时前
GitHub 10万星的OpenCode,正在悄悄改变我们的工作流
java·后端·程序员