【LeetCode】345.反转字符串中的元音字母

345.反转字符串中的元音字母

题目

原题链接

给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。

元音字母包括 'a''e''i''o''u',且可能以大小写两种形式出现不止一次。

示例 1:

1
2
输入: s = "hello"
输出:"holle"

示例 2:

1
2
输入: s = "leetcode"
输出:"leotcede"

提示:

  • 1 <= s.length <= 3 * 105
  • s可打印的 ASCII 字符组成

双指针法

同样的,我们使用双指针来进行遍历:定义一个开始下标(一般为0),并定义一个结束下标(字符串长度-1)。我们使用 开始下标从头向尾遍历,结束下标从尾向头遍历,当开始下标大于结束下标时结束遍历。

思路分析

我们假设传入字符串为s,那么我们定义一个元音的字符集合 arr ,然后定义开始下标 start 和结束下标 end ,并将其同时对向遍历,并定义一个长度为 s.length() 的新数组 res 来接收反转后的字符,那么我们由此可得:

  • arr 不包含 sstart 下标时的字符,也就是 sstart 下标时的字符不是元音字符,那么 res[start] 的值为 s 在下标 start 时的值。
  • 当上述条件不满足时,判断 arr 是否包含 send 下标时的字符,如果不包含说明 send 下标时的字符也不是元音字符,那么 res[end] 的值为 s 在下标 end 时的值。
  • 如果以上条件均不满足,也就是说 s 在下标 start 下和 end 下时的字符均为原因字符,那么将其调换位置即可,即:res[start] 的值为 send 下标时的值,而 res[end] 的值为 sstart 下标时的值。

注意:题目中提到了字符可能会出现大小写,且不止一次,那么我们同样要对大小写字符进行归类比较。

图解

未命名文件.gif

代码实现

实现一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static String reverseVowels(String s) {
List<Character> arr = Arrays.asList('a', 'e', 'i', 'o', 'u');
int start = 0;
int end = s.length() - 1;
char[] res = new char[s.length()];
while (start <= end) {
char startChar = s.charAt(start);
char endChar = s.charAt(end);
if (!arr.contains(Character.toLowerCase(startChar)) && !arr.contains(Character.toLowerCase(endChar))) {
res[start++] = startChar;
res[end--] = endChar;
} else if (!arr.contains(Character.toLowerCase(startChar)) && arr.contains(Character.toLowerCase(endChar))) {
res[start++] = startChar;
} else if (arr.contains(Character.toLowerCase(startChar)) && !arr.contains(Character.toLowerCase(endChar))) {
res[end--] = endChar;
} else {
res[start++] = endChar;
res[end--] = startChar;
}
}
return new String(res);
}

实现二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public String reverseVowels(String s) {
HashSet<Character> vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
if (s == null) return null;
int i = 0, j = s.length() - 1;
char[] result = new char[s.length()];
while (i <= j) {
char ci = s.charAt(i);
char cj = s.charAt(j);
if (!vowels.contains(ci)) {
result[i++] = ci;
} else if (!vowels.contains(cj)) {
result[j--] = cj;
} else {
result[i++] = cj;
result[j--] = ci;
}
}
return new String(result);
}

总结

利用 双指针法 来遍历字符串,所有元素只需要遍历一次即可得到预期结果,则时间复杂度为 O(n)。

额外变量只有 startend 两个,所以空间复杂度为 O(1)。