LeetCode 567 Permutation in String
题目分析
Given two strings
s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string’s permutations is the substring of the second string.
Example 1:
Input:s1 = "ab" s2 = "eidbaooo" Output:True Explanation: s2 contains one permutation of s1 ("ba").
Example 2:
Input:s1= "ab" s2 = "eidboaoo" Output: False
Note:
- The input strings only contain lower case letters.
- The length of both given strings is in range [1, 10,000].
题目足够简单,计算在字符串s2
中是否有s1
的某个排列。
思考
暴力计算的相信一定会超时的,毕竟计算一个字符串的排列可不是什么省时间的事,就算存放在列表里也不会提高太多效率,discuss里还有别的 O(n) O ( n ) 的算法如滑动窗口,我在这里说一个灰常简单的思路。
首先是利用全排列这个东西就可以了解到这个是求主串中是否有一个字串的字符和匹配串的字符全部相同(包含个数和种类),这个想到就可以继续向下了。
字符串哈希值相信大家都知道,哈希值的要求是对于同一个字符串得出的哈希值每次都是一样的,不一样的字符串尽量保证哈希值不相同,毕竟碰撞是不可避免的,这个题里就可以使用哈希的概念,将字符映射为哈希值,并将字符串也变为哈希值的和,在计算主串时就可以也计算同等长度的串是否哈希值和和匹配串相同,相同就可以返回true。
代码实现
class Solution {
// 26个随机数,不要问我是怎么得到的,python random模块了解一下
private static final long[] hashMap = {77886, 51044, 75120, 93338, 63245, 84866, 70301, 19244,
37029, 95036, 62918, 79389, 52211, 69968, 14003, 56270, 20747, 64639, 26711, 95751, 32553,
14959, 81792, 41986, 75273, 99929,};
public boolean checkInclusion(String s1, String s2) {
// 长度关系满足s1不比s2长
if (s1.length() > s2.length()) {
return false;
}
// 转换为字符数组,提高速度,下面不需要用到String库的方法
char[] cs1 = s1.toCharArray(), cs2 = s2.toCharArray();
// 记录两个字串的哈希值
long cs1hash = 0, cs2hash = 0;
for (int i = 0; i < cs1.length; i++) {
cs1hash += hashMap[cs1[i] - 'a'];
cs2hash += hashMap[cs2[i] - 'a'];
}
// 第一个先比较了
if (cs1hash == cs2hash) {
return true;
}
// 计算可以比较的次数
int len = cs2.length - cs1.length;
for (int i = 0; i < len; i++) {
// cs2迭代为新的哈希值
cs2hash += hashMap[cs2[i + cs1.length] - 'a'] - hashMap[cs2[i] - 'a'];
if (cs1hash == cs2hash) {
return true;
}
}
return false;
}
}
感想
关于字符串匹配,最有名的应该就是KMP了,但是KMP算法我见了太多次,发现根本学不会/(ㄒoㄒ)/~~,还好有另一个Robin-Karp指纹算法倒是看了一次就纪录下来了,就跟哈希值一样,计算字串的哈希值,主串中的字串哈希值都可以使用前面的在 O(1) O ( 1 ) 内求出来,效率还是比较高的,用在这里不需要考虑字串中字符的顺序了,乘除操作也就可以替换为加减了。