1 class Solution { 2 public int findTheLongestSubstring(String s) { 3 int n = s.length(); 4 Map<Character, Integer> map = new HashMap<>(); 5 map.put('a', 0); 6 map.put('e', 0); 7 map.put('i', 0); 8 map.put('o', 0); 9 map.put('u', 0); 10 int l = 0, maxlen = 0; 11 for (int r = 0; r < n; r++) { 12 char curr = s.charAt(r); 13 if (map.containsKey(curr)) { 14 map.put(curr, map.get(curr) + 1); 15 } 16 Map<Character, Integer> temp = new HashMap<>(); 17 18 temp.put('a', map.get('a')); 19 temp.put('e', map.get('e')); 20 temp.put('i', map.get('i')); 21 temp.put('o', map.get('o')); 22 temp.put('u', map.get('u')); 23 24 while (temp.get('a') % 2 == 1 || temp.get('e') % 2 == 1 || temp.get('i') % 2 == 1 || temp.get('o') % 2 == 1 25 || temp.get('u') % 2 == 1) { 26 char left = s.charAt(l); 27 if (temp.containsKey(left)) { 28 temp.put(left, temp.get(left) - 1); 29 } 30 l++; 31 } 32 maxlen = Math.max(maxlen, r - l + 1); 33 l = 0; 34 } 35 return maxlen; 36 } 37 }
算法思路:滑动窗口。
分析:两层循环,外层确定右边界,内层确定左边界。
每次外层循环,都复制一份元音字母个数的字典放到temp中。判断当前状态是否存在某个元音字符的个数是奇数个。
如果存在这样的元音字符,则将左边界向右移动,一直到所有元音字符都是偶数个为止。此时找到一种解决方案,跳出循环。
计算此时的字串的长度,并更新最大长度字段maxlen。
可见这种解决方案的时间复杂度是O(n*n),效率比较低。
在leetcode上的执行结果为:
第二种方案:
1 class Solution { 2 public int findTheLongestSubstring(String s) { 3 int res = 0 , cur = 0, n = s.length(); 4 HashMap<Integer, Integer> seen = new HashMap<>(); 5 seen.put(0, -1); 6 for (int i = 0; i < n; ++i) { 7 cur ^= 1 << ("aeiou".indexOf(s.charAt(i)) + 1 ) >> 1; 8 seen.putIfAbsent(cur, i); 9 res = Math.max(res, i - seen.get(cur)); 10 } 11 return res; 12 } 13 }
算法思路:位运算。
分析:这应该是本题的比较好的解决方案。
在leetcode上的执行结果:
与第一种方案对比,执行效率高了很多,但不太容易理解。