LeetCode #438 找到字符串中所有字母异位词

题目给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。

字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string

示例

在这里插入图片描述

最佳代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author vleus
 * @date 2021年05月13日 22:51
 */
public class FindALLAnagrams {

    //方法一: 枚举所有长度为p.length()的子串
    public List<Integer> findAnagrams1(String s, String p) {

        //定义一个结果列表
        ArrayList<Integer> result = new ArrayList<>();

        //1、统计p中所有字符出现的频次
        int[] pCharCounts = new int[26];

        for (int i = 0; i < p.length(); i++) {
            pCharCounts[p.charAt(i) - 'a']++;
        }

        //2、遍历s,以每一个字符作为起始,考察长度为p.length()的子串
        for (int i = 0; i <= s.length() - p.length(); i++) {
            //3、判断当前子串是否为p的字母异位词
            boolean isMatched = true;

            int[] subStrCharCounts = new int[26];
            for (int j = i; j < i + p.length(); j++) {
                subStrCharCounts[s.charAt(j) - 'a']++;

                //判断当前字符频次如果超过了p中的频次,就一定不符合要求
                if(subStrCharCounts[s.charAt(j) - 'a'] > pCharCounts[s.charAt(j) - 'a']){
                    isMatched = false;
                    break;
                }
            }
            if (isMatched) {
                result.add(i);
            }
        }
        return result;
    }

    //方法二:滑动窗口法,分别移动起始和结束位置
    public List<Integer> findAnagrams(String s, String p) {

        //定义一个结果列表
        ArrayList<Integer> result = new ArrayList<>();

        //1、统计p中所有字符出现的频次
        int[] pCharCounts = new int[26];

        for (int i = 0; i < p.length(); i++) {
            pCharCounts[p.charAt(i) - 'a']++;
        }

        //统计子串中所有字符出现频次的数组
        int[] subStrCharCounts = new int[26];

        //定义起始和结束位置
        int start = 0,end = 1;
        //2.移动指针,总是截取字符串出现频次全部小于等于p中字符频次的子串
        while (end <= s.length()) {
            char newChar = s.charAt(end - 1);
            subStrCharCounts[newChar - 'a']++;

            //3.判断当前子串是否符合要求
            //如果新增字符导致子串频次超出了p中频次,那么移动start,消除新增的字符的影响
            while (subStrCharCounts[newChar - 'a'] > pCharCounts[newChar - 'a'] && start < end) {
                char removedChar = s.charAt(start);
                subStrCharCounts[removedChar - 'a']--;
                start++;
            }

            //如果当前子串等于p的长度,那么就是一个字母异位词
            if (end - start == p.length()) {
                result.add(start);
            }

            end++;
        }

        return result;
    }

    public static void main(String[] args) {

        String s = "cbaebabacd";
        String p = "abc";

        FindALLAnagrams findALLAnagrams = new FindALLAnagrams();

        System.out.println(Arrays.toString(findALLAnagrams.findAnagrams(s,p).toArray()));

    }
}
滑动窗口是一种常用的算法技巧,可以用于解决一类问题,其包括一些LeetCode上的题目。通过维护一个窗口,我们可以在线性时间内解决一些需要处理连续子数组或子字符串的问题。以下是一些常见的滑动窗口问题: 1. 最小覆盖子串(Minimum Window Substring):给定一个字符串S和一个字符串T,在S找出包含T所有字符的最小子串。 2. 字符串的排列(Permutation in String):给定两个字符串s1和s2,判断s2是否包含s1的排列。 3. 找到字符串所有字母异位(Find All Anagrams in a String):给定一个字符串s和一个非空字符串p,找到s所有是p的字母异位的子串。 4. 替换后的最长重复字符(Longest Repeating Character Replacement):给定一个只包含大写英文字母字符串s,你可以将一个字母替换成任意其他字母,使得包含重复字母的最长子串的长度最大化。 5. 至多包含两个不同字符的最长子串(Longest Substring with At Most Two Distinct Characters):给定一个字符串s,找出至多包含两个不同字符的最长子串的长度。 以上只是几个例子,滑动窗口可以应用于更多类型的问题。在解决这些问题时,我们通常使用两个指针来表示窗口的左右边界,并根据具体问题的要求移动窗口。在每次移动窗口时,我们可以更新窗口的状态,例如统计字符出现次数、判断窗口是否满足条件等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值