(leetcode) 力扣100 9.找到字符串中所有字母异位词(滑动窗口)
题目
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
数据范围
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母
样例
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
题解
博主题解(时间复杂度:O(m+(n−m)×Σ),其中 n 为字符串 s 的长度,m 为字符串 p 的长度,Σ 为所有可能的字符数(26个小写字母)。) 与官方题解思路一致,唯一区别就是写代码的习惯
class Solution {//记录遍历过程中的hash数组 static int at[];//记录p的哈希数组static int ap[];public List<Integer> findAnagrams(String s, String p) {at=new int[27];ap=new int[27];List<Integer> res=new LinkedList<>();if(s.length()<p.length())return res;int lenp=p.length();int lens=s.length();int ti=0;char cp[]=p.toCharArray();char cs[]=s.toCharArray();for(int i=0;i<cp.length;i++)ap[cp[i]-96]++;while(ti<lenp){at[cs[ti]-96]++;ti++;}if(check()){res.add(0);}int l=1;int r=lenp;while(r<lens){at[cs[l-1]-96]--;at[cs[r]-96]++;if(check())res.add(l);l++;r++;}return res;}public boolean check(){boolean flag=true;for(int i=1;i<=26;i++){if(ap[i]!=at[i]){flag=false;break;}}return flag;}
}
官方题解二(官方题解一与我的方法近乎一致,就不重复了,题解二时间复杂度O(n+m+Σ))
class Solution {public List<Integer> findAnagrams(String s, String p) {int sLen = s.length(), pLen = p.length();if (sLen < pLen) {return new ArrayList<Integer>();}List<Integer> ans = new ArrayList<Integer>();int[] count = new int[26];for (int i = 0; i < pLen; ++i) {++count[s.charAt(i) - 'a'];--count[p.charAt(i) - 'a'];}int differ = 0;for (int j = 0; j < 26; ++j) {if (count[j] != 0) {++differ;}}if (differ == 0) {ans.add(0);}for (int i = 0; i < sLen - pLen; ++i) {if (count[s.charAt(i) - 'a'] == 1) { // 窗口中字母 s[i] 的数量与字符串 p 中的数量从不同变得相同--differ;} else if (count[s.charAt(i) - 'a'] == 0) { // 窗口中字母 s[i] 的数量与字符串 p 中的数量从相同变得不同++differ;}--count[s.charAt(i) - 'a'];if (count[s.charAt(i + pLen) - 'a'] == -1) { // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从不同变得相同--differ;} else if (count[s.charAt(i + pLen) - 'a'] == 0) { // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从相同变得不同++differ;}++count[s.charAt(i + pLen) - 'a'];if (differ == 0) {ans.add(i + 1);}}return ans;}
}作者:力扣官方题解
链接:https://leetcode.cn/problems/find-all-anagrams-in-a-string/solutions/1123971/zhao-dao-zi-fu-chuan-zhong-suo-you-zi-mu-xzin/
来源:力扣(LeetCode)
思路
这道题很简单,个人认为不应该列入普通难度,因为这道题近乎没有思维难度,题目描述就是解题方法,我们们要做的也就是遍历数组,用滑动窗口维持p字符串的空间,然后将窗口内的子串与p对比就行了。
博主的思路就是简单的用hash存储窗口的子串与目标串,然后自写check()方法判断是否相同(也可以用官方题解的Arrays.equal判断,博主事先不知道这个方法)。 这个方法虽然简单,但够用。两种复杂度也达标。
官方的解法二十分巧妙,进一步优化了时间复杂度,他节约了每次去对比子串的时间,用一个变量differ从头到尾维护子串与目标串不同字符的个数,从而更加节约时间。