题目:

Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.

Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.

The order of output does not matter.

Example 1:

Input:

s: "cbaebabacd" p: "abc"

Output:

[0, 6]

Explanation:

The substring with start index = 0 is "cba", which is an anagram of "abc".

The substring with start index = 6 is "bac", which is an anagram of "abc".

Example 2:

Input:

s: "abab" p: "ab"

Output:

[0, 1, 2]

Explanation:

The substring with start index = 0 is "ab", which is an anagram of "ab".

The substring with start index = 1 is "ba", which is an anagram of "ab".

The substring with start index = 2 is "ab", which is an anagram of "ab".

解题思路:

这道题一个最重要的难点就是时间控制。另一个就是哈希表的应用。

笔者第一次是从s中逐步截取与p等长的子串m,然后再暴力遍历分析m和p是否为Anagrams(只有字符顺序不同的两个字符串),总的时间复杂度为O(s*p*p)大概是O(n^3),自然不能通过。第二次时间优化是在比较m和p时,采用《如何判断两个String是否是Anagrams》一文中介绍的方法,总的时间复杂度是O(s*p),大概是O(n^2),然后依然没有通过,超时。

最后一次进一步优化,使用滑动窗口,使得时间复杂度为为O(n),这就是算法的力量!

算法介绍:

(1)NumberOfDeference = p.length(),用来表示目前窗口中的字符和p的差异度(由于窗口最大时(为p.length())才有可能使NumberOfDeference为0,所以NumberOfDeference 为0时窗口中与p为Anagrams)。NumberOfDeference差异度的含义:一开始窗口左右指针都指向第一个,所以差异度最大为p.length();当窗口中进来一个p中有的字符,差异度就减一,出去一个有的差异度就增一;至于进来或出去的是p中没有的则NumberOfDeference不变,反正窗口的最大值也不过是p.length()。

(2)窗口的左右两个指针:left和right,分别指向窗口的左端和右端。

滑动窗口具体操作:

先滑动右指针,

1.1 加进来的字符如果该字符在数组asciiChars的计数中非负,则NumberOfDeference减一,否则不做操作,

1.2无论在不在数组asciiChars该字符相应位置计数都减一

1.3如果滑动完right,判断如果窗口长度到达p.length()(如果长度到达p.length(),并且NumberOfDeference为0,则将此时的left值加入到result中),滑动左窗口。

滑动左指针:

2.1被踢出窗口的那个字符如果在数组asciiChars的计数中非负,则NumberOfDeference增一,不在则不做操作。

2.2无论在不在数组asciiChars该字符相应位置计数都加一

(3)上面1.1和2.1操作的原理:asciiChars中的记录的数据是代表p中含有的的每个字符的数量去掉当前窗口中存在的p字符串中每个字符的数量,一开始窗口大小为0,啥都不存在,自然asciiChars中记录的就是全部p中含有的的每个字符的数量,如果窗口中有一个,则asciiChars相应的记录中就少一个。如果窗口中多包含一个p中没有的(或者包含的某一个字符的数量比p中有的还多),那么这时候,asciiChars中相应的记录值就会变成负数,代表当前窗口中包含相应字符的“多余”的数量。

所以当进来一个的时候,如果相应记录为非负,那么这个进入是有意义的,则差异度(NumberOfDeference)减一;当出去一个的时候,如果相应记录为非负,那么这个出去是有意义的,则差异度(NumberOfDeference)加一。

(4)asciiChars用到哈希表思想,用来记录p中每一种字符分别有多少个。详见《如何判断两个String是否是Anagrams》一文。

代码:

public static List<Integer> findAnagrams(String s, String p) {
List<Integer> result = new ArrayList<Integer>();
int NumberOfDeference = p.length(); //差异度指数
int left=0,right=0; //窗口左右指针
int[] asciiChars = new int[256];
//记录p中字符有哪些及其数量的数组
for (int i = p.length() - 1; i>=0; --i)
{ ++asciiChars[p.charAt(i)]; } //记录完毕 for(;right<s.length();right++){ //滑动右窗口
asciiChars[s.charAt(right)]--; //在该字符相应位置减一
if(asciiChars[s.charAt(right)]>=0) NumberOfDeference--;
//如果加进来的那个在p中,NumberOfDeference减一
if(right-left == (p.length()-1)){
//如果这时窗口大小为p.length()
if(NumberOfDeference==0) result.add(left);
//这时出现一次匹配,将左窗口加到result中
//下面是滑动左窗口的操作
if(asciiChars[s.charAt(left)]>=0) {
NumberOfDeference++;
//如果被踢出的那个在p中,NumberOfDeference加一
}
asciiChars[s.charAt(left)]++;
//数组中相应字符计数位置加回来
left++; //左窗口向右滑动
}
}
return result;
}

leetcode_438_Find All Anagrams in a String_哈希表_java实现的更多相关文章

  1. 【字符串哈希】【哈希表】Aizu - 1370 - Hidden Anagrams

    给你两个4k长度的串,问你最长公共子串.两个子串相同被定义为所有字母的出现次数分别相同即可. 就枚举第一个串的所有子串,将字母出现的次数看作一个大数,进行哈希(双关键字),塞到哈希表里面.然后枚举第二 ...

  2. 算法与数据结构基础 - 哈希表(Hash Table)

    Hash Table基础 哈希表(Hash Table)是常用的数据结构,其运用哈希函数(hash function)实现映射,内部使用开放定址.拉链法等方式解决哈希冲突,使得读写时间复杂度平均为O( ...

  3. C#LeetCode刷题-哈希表

    哈希表篇 # 题名 刷题 通过率 难度 1 两数之和 C#LeetCode刷题之#1-两数之和(Two Sum) 42.8% 简单 3 无重复字符的最长子串   24.2% 中等 18 四数之和   ...

  4. [PHP内核探索]PHP中的哈希表

    在PHP内核中,其中一个很重要的数据结构就是HashTable.我们常用的数组,在内核中就是用HashTable来实现.那么,PHP的HashTable是怎么实现的呢?最近在看HashTable的数据 ...

  5. Java 哈希表运用-LeetCode 1 Two Sum

    Given an array of integers, find two numbers such that they add up to a specific target number. The ...

  6. ELF Format 笔记(十五)—— 符号哈希表

    ilocker:关注 Android 安全(新手) QQ: 2597294287 符号哈希表用于支援符号表的访问,能够提高符号搜索速度. 下表用于解释该哈希表的组织,但该格式并不属于 ELF 规范. ...

  7. Java基础知识笔记(一:修饰词、向量、哈希表)

    一.Java语言的特点(养成经常查看Java在线帮助文档的习惯) (1)简单性:Java语言是在C和C++计算机语言的基础上进行简化和改进的一种新型计算机语言.它去掉了C和C++最难正确应用的指针和最 ...

  8. 什么叫哈希表(Hash Table)

    散列表(也叫哈希表),是根据关键码值直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. - 数据结构 ...

  9. 【哈希表】CodeVs1230元素查找

    一.写在前面 哈希表(Hash Table),又称散列表,是一种可以快速处理插入和查询操作的数据结构.哈希表体现着函数映射的思想,它将数据与其存储位置通过某种函数联系起来,其在查询时的高效性也体现在这 ...

随机推荐

  1. BI之SSAS完整实战教程5 -- 详解多维数据集结构

    之前简单介绍过多维数据集(Cube)的结构. 原来计划将Cube结构这部分内容打散,在实验中穿插讲解, 考虑到结构之间不同的部分都有联系,如果打散了将反而不好理解,还是直接一次性全部讲完. 本篇我们将 ...

  2. 解决IIS Web部署 svg/woff/woff2字体 404错误

    最近在IIS上部署web项目的时候,发现浏览器总是报找不到woff.woff2字体的错误.导致浏览器加载字体报404错误,白白消耗了几百毫秒的加载时间. 一开始以为是路径的问题,检查发现路径也没错. ...

  3. sql server2008中sql server身份能登录,window身份登录不了

    用sql server身份的sa登录成功进入,一切正常,用window身份登录不了,问题如下

  4. 【原创】C#通用权限管理-程序安全检查,这些你一定要考虑到位

    接触通用权限已经一年,现在使用已经很熟练,分享通用权限管理下面的一些好的开发思想. 安全漏洞对于一个小项目来说,可能不是特别的重视,对于一个大项目来说,这是特别重要需要注意的,特别是在项目开发中的就要 ...

  5. mvc设计模式和mvc框架的区别

    Spring中的新名称也太多了吧!IOC/DI/MVC/AOP/DAO/ORM... 对于刚刚接触spring的我来说确实晕了头!可是一但你完全掌握了一个概念,那么它就会死心塌地的为你服务了.这可比女 ...

  6. stl空间配置器线程安全问题补充

    摘要 在上一篇博客<STL空间配置器那点事>简单介绍了空间配置器的基本实现 两级空间配置器处理,一级相关细节问题,同时简单描述了STL各组件之间的关系以及设计到的设计模式等. 在最后,又关 ...

  7. [Azure] Notification Hubs注册模式

    [Azure] Notification Hubs注册模式 关于Azure Notification Hubs的注册模式,可以参考下列连结的文件内容. Notification Hubs Featur ...

  8. 你可以使用 play framework 做5件很爽的事情http://www.anool.net/?p=629

    1.绑定HTTP参数到JAVA方法里的参数. 使用PLAY可以很简单的从JAVA代码中检索HTTP参数.只要把方法参数申明成和HTTP参数相同既可. 比如,这个request: Http代码 /art ...

  9. JS中标准对象

    JS中标准对象1:不要使用new Number().new Boolean().new String()创建包装对象:2:用parseInt()或parseFloat()来转换任意类型到number: ...

  10. 关于iChartjs在移动端提示框tip显示不正常的解决方法

    最近项目需要使用手机图表,但是找了很久都没找到专门为移动端开发的图表,只能找一些能兼容移动端的图表控件,今天就讲讲关于iChartjs这个图形库的一点问题. 问题 iChartjs的提示框tip的显示 ...