【算法分析与设计】找到字符串中所有字母异位词

题目

给定两个字符串 sp,找到 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" 的异位词。

方案一:

算法设计与分析

在字符串s中找到给定字符串p的所有字母异位词的Java解决方案。findAnagrams方法遍历s中每个长度为p的可能子字符串,并使用isTrue方法检查它是否是p的字母异位词。isTrue方法对两个字符串的字符数组进行排序,然后进行比较。

算法实现
java 复制代码
class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        String str;
        List<Integer> list=new ArrayList();
        for(int i=0;i<s.length();i++){
            if(i>s.length()-p.length()){
                break;
            }
            str=s.substring(i,i+p.length());
            if(isTrue(str,p)){
                list.add(i);
            }
        }

        return list;
    }
    public Boolean isTrue(String p,String q){
    
        char[] parr= p.toCharArray();
        char[] qarr= q.toCharArray();
        Arrays.sort(parr);
        Arrays.sort(qarr);
        String ps=new String(parr);
        String qs=new String(qarr);
        
        return ps.equals(qs)?true:false;

    }
}
运行结果:

超时。。。

调优

思想(优化后的算法)

采用的是滑动窗口(Sliding Window)算法,这是一种常见的解决子字符串或子数组问题的技术。滑动窗口算法通过维护一个可变大小的窗口在序列上滑动,并在每个位置上执行必要的操作,从而达到解决问题的目的。

在这个具体的问题中,滑动窗口的目标是找到字符串 s 中所有是字符串 p 的字母异位词的子串的起始索引。这里的关键思想是使用两个数组 pCountwindowCount 来分别统计字符串 p 和当前滑动窗口中子字符串的字符频率。

滑动窗口算法通常具有较好的时间复杂度,因为在每一步中,只需要对窗口中新增或移除的元素进行常量时间的操作。在这个特定问题中,使用滑动窗口避免了对整个字符串进行排序,从而将时间复杂度降低到线性级别。

算法调优
  1. 字符频率统计:

    • 使用两个整数数组pCountwindowCount,分别用于统计字符串p和滑动窗口中当前子字符串的字符频率。这两个数组的索引对应字母表中的字母,而数组中的值表示相应字母的出现次数。
  2. 初始化 pCount

    • 在第一个循环中,对字符串p进行遍历,并更新pCount数组中相应字母的频率。
  3. 滑动窗口:

    • 在第二个循环中,遍历字符串s。对于每个字符,将其在windowCount中的频率递增。
    • 如果窗口的大小超过了p的长度,就需要将窗口最左侧字符在windowCount中的频率递减,以保持窗口大小不变。
    • 这样,我们通过一个固定大小的窗口在字符串s上滑动,每次只更新一个字符的频率,而不是重新计算整个子字符串的频率。
  4. 比较频率:

    • 在每一步,通过比较pCountwindowCount数组是否相等来检查当前子字符串是否为p的字母异位词。
    • 如果相等,表示找到了一个字母异位词的起始索引。

通过这种方式,避免了对字符串进行排序,而是通过数组直接比较字符频率,大大提高了算法的效率。这种滑动窗口的方法在处理子字符串问题时通常非常有效,因为它在遍历过程中只对每个字符进行一次操作。

思路图

删去c 加入e如下变换

其他类推...

代码实现
java 复制代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> result = new ArrayList<>();

        int[] pCount = new int[26];
        int[] windowCount = new int[26];

        for (char ch : p.toCharArray()) {
            pCount[ch - 'a']++;
        }

        for (int i = 0; i < s.length(); i++) {
            windowCount[s.charAt(i) - 'a']++;

            if (i >= p.length()) {
                windowCount[s.charAt(i - p.length()) - 'a']--;
            }

            if (Arrays.equals(pCount, windowCount)) {
                result.add(i - p.length() + 1);
            }
        }

        return result;
    }
}
运行结果
相关推荐
醉颜凉20 分钟前
【NOIP提高组】潜伏者
java·c语言·开发语言·c++·算法
阿维的博客日记24 分钟前
java八股-jvm入门-程序计数器,堆,元空间,虚拟机栈,本地方法栈,类加载器,双亲委派,类加载执行过程
java·jvm
qiyi.sky25 分钟前
JavaWeb——Web入门(8/9)- Tomcat:基本使用(下载与安装、目录结构介绍、启动与关闭、可能出现的问题及解决方案、总结)
java·前端·笔记·学习·tomcat
lapiii35828 分钟前
图论-代码随想录刷题记录[JAVA]
java·数据结构·算法·图论
RainbowSea31 分钟前
4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明
java·spring·spring cloud
程序员小明z32 分钟前
基于Java的药店管理系统
java·开发语言·spring boot·毕业设计·毕设
爱敲代码的小冰1 小时前
spring boot 请求
java·spring boot·后端
Lyqfor1 小时前
云原生学习
java·分布式·学习·阿里云·云原生
程序猿麦小七1 小时前
今天给在家介绍一篇基于jsp的旅游网站设计与实现
java·源码·旅游·景区·酒店
Dontla2 小时前
Rust泛型系统类型推导原理(Rust类型推导、泛型类型推导、泛型推导)为什么在某些情况必须手动添加泛型特征约束?(泛型trait约束)
开发语言·算法·rust