[LeetCode] 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].
这道题给了两个字符串s1和s2,问我们s1的全排列的字符串任意一个是否为s2的字串。虽然题目中有全排列的关键字,但是跟之前的全排列的题目的解法并不一样,如果受思维定势影响比较深的话,很容易遍历s1所有全排列的情况,然后检测其是否为s2的子串,这种解法是非常不高效的,估计OJ不会答应。 这道题的正确做法应该是使用滑动窗口Sliding Window的思想来做,可以使用两个哈希表来做,或者是使用一个哈希表配上双指针来做。我们先来看使用两个哈希表来做的情况,我们先来分别统计s1和s2中前n1个字符串中各个字符出现的次数,其中n1为字符串s1的长度,这样如果二者字符出现次数的情况完全相同,说明s1和s2中前n1的字符互为全排列关系,那么符合题意了,直接返回true。如果不是的话,那么我们遍历s2之后的字符,对于遍历到的字符,对应的次数加1,由于窗口的大小限定为了n1,所以每在窗口右侧加一个新字符的同时就要在窗口左侧去掉一个字符,每次都比较一下两个哈希表的情况,如果相等,说明存在,参见代码如下:
解法一:
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int n1 = s1.size(), n2 = s2.size();
vector<int> m1(), m2();
for (int i = ; i < n1; ++i) {
++m1[s1[i]]; ++m2[s2[i]];
}
if (m1 == m2) return true;
for (int i = n1; i < n2; ++i) {
++m2[s2[i]];
--m2[s2[i - n1]];
if (m1 == m2) return true;
}
return false;
}
};
下面这种解法是利用一个哈希表加上双指针,我们还是先统计s1中字符的出现次数,然后遍历s2中的字符,对于每个遍历到的字符,我们在哈希表中对应的字符次数减1,如果次数次数小于0了,说明该字符在s1中不曾出现,或是出现的次数超过了s1中的对应的字符出现次数,那么我们此时移动滑动窗口的左边界,对于移除的字符串,哈希表中对应的次数要加1,如果此时次数不为0,说明该字符不在s1中,继续向右移,直到更新后的次数为0停止,此时到达的字符是在s1中的。如果次数大于等于0了,我们看此时窗口大小是否为s1的长度,若二者相等,由于此时窗口中的字符都是在s1中存在的字符,而且对应的次数都为0了,说明窗口中的字符串和s1互为全排列,返回true即可,参见代码如下:
解法二:
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int n1 = s1.size(), n2 = s2.size(), left = ;
vector<int> m();
for (char c : s1) ++m[c];
for (int right = ; right < n2; ++right) {
if (--m[s2[right]] < ) {
while (++m[s2[left++]] != ) {}
} else if (right - left + == n1) return true;
}
return n1 == ;
}
};
下面这种解法也是用一个哈希表外加双指针来做的,跟上面的解法思路大体相同,写法有些不同,不变的还是统计s1中字符出现的次数,不一样的是我们用一个变量cnt来表示还需要匹配的s1中的字符的个数,初始化为s1的长度,然后遍历s2中的字符,如果该字符在哈希表中存在,说明匹配上了,cnt自减1,哈希表中的次数也应该自减1,然后如果cnt减为0了,说明s1的字符都匹配上了,如果此时窗口的大小正好为s1的长度,那么说明找到了s1的全排列,返回true,否则说明窗口过大,里面有一些非s1中的字符,我们将左边界右移,同时将移除的字符串在哈希表中的次数自增1,如果增加后的次数大于0了,说明该字符是s1中的字符,我们将其移除了,那么cnt就要自增1,参见代码如下:
解法三:
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int n1 = s1.size(), n2 = s2.size(), cnt = n1, left = ;
vector<int> m();
for (char c : s1) ++m[c];
for (int right = ; right < n2; ++right) {
if (m[s2[right]]-- > ) --cnt;
while (cnt == ) {
if (right - left + == n1) return true;
if (++m[s2[left++]] > ) ++cnt;
}
}
return false;
}
};
类似题目:
参考资料:
https://discuss.leetcode.com/topic/87856/sliding-window-o-n-c
https://discuss.leetcode.com/topic/87845/java-solution-sliding-window
https://discuss.leetcode.com/topic/87861/c-java-clean-code-with-explanation
https://discuss.leetcode.com/topic/87884/8-lines-slide-window-solution-in-java
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Permutation in String 字符串中的全排列的更多相关文章
- [LeetCode] 567. Permutation in String 字符串中的全排列
Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. I ...
- String 字符串中含有 Unicode 编码时,转为UTF-8
1.单纯的Unicode 转码 String a = "\u53ef\u4ee5\u6ce8\u518c"; a = new String(a.getBytes("UTF ...
- 将string字符串中的换行符进行替换
/** * 方法名称:replaceBlank * 方法描述: 将string字符串中的换行符进行替换为"" * */ public static String replaceBl ...
- [LeetCode] Add Bold Tag in String 字符串中增添加粗标签
Given a string s and a list of strings dict, you need to add a closed pair of bold tag <b> and ...
- LeetCode 557:反转字符串中的单词 III Reverse Words in a String III
公众号:爱写bug(ID:icodebugs) 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序. Given a string, you need to reve ...
- 434 Number of Segments in a String 字符串中的单词数
统计字符串中的单词个数,这里的单词指的是连续的非空字符.请注意,你可以假定字符串里不包括任何不可打印的字符.示例:输入: "Hello, my name is John"输出: 5 ...
- [CareerCup] 1.1 Unique Characters of a String 字符串中不同的字符
1.1 Implement an algorithm to determine if a string has all unique characters. What if you cannot us ...
- String:(字符串)中常用的方法
package stringyiwen; //字符串中常用的方法public class StringTest03 { public static void main(String[] args) { ...
- Leetcode434.Number of Segments in a String字符串中的单词数
统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符. 请注意,你可以假定字符串里不包括任何不可打印的字符. 示例: 输入: "Hello, my name is John" ...
随机推荐
- linux小白成长之路3————更新yum源
[内容指引] 进入目录:cd 查看目录下的内容:ls 重命名备份:mv 从网络下载:wget yum更新:yum update 第一次运行yum安装软件前,建议更新yum. 1.进入yum源目录 命令 ...
- java 对象和封装
软件出现的目的 面向对象设计和开发程序的好处用计算机语言描述现实世界 交流更加流畅用计算机解决现实世界的问题 提高设计和开发效率 面向对象的思想 描述→ 面向对象的世界 ...
- Jedis操作Redis
Jedis操作Redis的常用封装方法 @Resource(name="jedispool") private JedisPool pool=null; /** * 设置缓存对象过 ...
- linux小白成长之路10————SpringBoot项目部署进阶
[内容指引] war包部署: jar包部署: 基于Docker云部署. 一.war包部署 通过"云开发"平台初始化的SpringBoot项目默认采用jar形式打包,这也是我们推荐的 ...
- C语言函数嵌套调用作业总结
成绩管理系统作业小结 devc中出现"ID Return"问题,我帮很多同学看完后发现,大部分还是自身程序问题,如全局变量大小写错误.没有添加c文件进工程等等.所以对于" ...
- C语言函数嵌套调用作业
一.实验作业 1.1 PTA题目:6-4 十进制转换二进制 设计思路 如果n大于1 对n/2继续进行该函数运算 输出n%2的值 代码截图 调试问题 我第一次做的时候判断的边界条件是大于0继续进行运算, ...
- Ubuntu下安装gsoap
昨天在ubuntu下进行安装gSOAP,费了很多时间,没成功,今天又来找了大量教程资料,终于一次成功,这里写下自己的安装步骤和方法,供大家参考. 首先下载gsoap,我下载的是gsoap-2.8.1. ...
- TCP和UDP的最完整的区别
TCP UDP TCP与UDP基本区别 1.基于连接与无连接 2.TCP要求系统资源较多,UDP较少: 3.UDP程序结构较简单 4.流模式(TCP)与数据报模式(UDP); ...
- 51Nod P1100 斜率最大
传送门: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1100 由于2 <= N <= 10000, 所以 ...
- xxe漏洞检测及代码执行过程
这两天看了xxe漏洞,写一下自己的理解,xxe漏洞主要针对webservice危险的引用的外部实体并且未对外部实体进行敏感字符的过滤,从而可以造成命令执行,目録遍历等.首先存在漏洞的web服务一定是存 ...