2020.5.20每个元音包含偶数次的最长子字符串
默认格式:
class Solution {
public int findTheLongestSubstring(String s) {
}
}
解题思路:
这道题的题目略长,理解起来也比较费劲,大致的意思就是要在给的字符串中找出一个字符串,这个字符串中的a,e,i,o,u五个字母都出现了偶数次。
这道题其实和之前写的乘积最大的子数组,和为k的子数组都有一些类似的东西,就是在数组中找一个子数组,如果是数字的话应该是找一个公式,如果是字符串的话就没有办法了,只能找规律。
那就思考一下,有什么规律在其中呢?
首先,字母只有两种状态,前面的是奇数个,前面的是偶数个,那么我们可以记下0-每个字母前面的元音字母个数
比如下面一个字符串
leetcodeisgreat
我们在00000处记下0 表示全都是偶数的起点是0
然后l处不计算,因为他是奇数,对结果是没有影响的
然后在e处记录01000 2表示只有e为奇数的情况是在下标为2的地方为起点
然后又是一个e记下00000 3表示此处是前面所有都是偶数,这里的3代表的是终点
然后t、c直接跳过,遇到o :00010 6
e:01010 8
i:01110 9
a:11110 14
然后在这个数组里找到相同的两个离得最远的,那就是00000 0和00000 3 此时就可以得到最长的串就是0-3,但是要加上辅音的部分,所以从0开始往前找,同时从3开始往右找,找到第一个辅音字母为止。那就是找到o之前,也就是找到了4的位置,此时得到长度就是4
想法是有了,接下来如何实现,为了能够通过状态找到与其想对应的位置,那么应该使用map来存,而要存五个状态很明显是不可能的,所以,很明显,为什么我上面用了1和0来表示,因为我决定用数字来表示状态,状态一共有2^5种,然后在其中存入两个数字,一个是起始位置,一个是结尾位置,在遍历完字符串之后,我们就得到了所有可能的组合的起始位置和结束位置
然后我们遍历这个集合,计算起始位置和结束位置的差最大的那一个
得到那一个状态的起始位置和结束位置,然后分别向前和向后测试,找到第一个元音字母为止,这样就找到了最大的大小。
实现部分:(答案错误)
说实话,这种算法解得真的不好,除了锻炼一下逻辑思维能力几乎就没用了,自己找的规律漏洞百出,在提交失败之后修改,改出来又是错的,改来改去发现已经不知道哪里有错了。
不过我一定会回来修改的,找到问题在哪,今天就先把他提交了把
class Solution {
public int findTheLongestSubstring(String s) {
//做一个map来装数据
HashMap<Integer,int[]> map=new HashMap<Integer,int[]>();
char[] chars=s.toCharArray();
int status=0;
//第一个的位置是0,0,好理解
map.put(0,new int[2] );
int length=0;
int st=0;
//开始遍历数组,里面的判断会比较麻烦,在遍历的时候记住间隔,间隔大的设为长度
for (int i=0;i<chars.length;i++){
//这里如何减少判断的次数?用else if可以在遇到第一个符合的时候跳出判断
if(chars[i]=='a')
{
//异或运算,修改状态
st=0;
status=status^16;
//看一下这个状态出现过没有,如果没有出现过,将该地址设置为他的起始地址
if (map.get(status)==null){
//状态码的信息,i+1是字母的起始位置,-1是末尾位置的初值,如果最后计算时还是-1表示该状态没有出现过第二次,
// 不过实际应该用不到,找后面减前面的最小值,正常最小值是0,而后面如果是-1的话,最小值会小于0,这就意味
//着他的长度永远不会是最长的,所以不用计算
int[] array={
i+1,-1};
map.put(status, array);
}
else
//直接改内容是可以改掉的
map.get(status)[1]=i+1;
}
else if(chars[i]=='e'){
st=0;
status=status