leetcode
leetcode 2401 ~ 2450
将字符串中的元音字母排序

将字符串中的元音字母排序

难度:

标签:

题目描述

Given a 0-indexed string s, permute s to get a new string t such that:

  • All consonants remain in their original places. More formally, if there is an index i with 0 <= i < s.length such that s[i] is a consonant, then t[i] = s[i].
  • The vowels must be sorted in the nondecreasing order of their ASCII values. More formally, for pairs of indices i, j with 0 <= i < j < s.length such that s[i] and s[j] are vowels, then t[i] must not have a higher ASCII value than t[j].

Return the resulting string.

The vowels are 'a', 'e', 'i', 'o', and 'u', and they can appear in lowercase or uppercase. Consonants comprise all letters that are not vowels.

 

Example 1:

Input: s = "lEetcOde"
Output: "lEOtcede"
Explanation: 'E', 'O', and 'e' are the vowels in s; 'l', 't', 'c', and 'd' are all consonants. The vowels are sorted according to their ASCII values, and the consonants remain in the same places.

Example 2:

Input: s = "lYmpH"
Output: "lYmpH"
Explanation: There are no vowels in s (all characters in s are consonants), so we return "lYmpH".

 

Constraints:

  • 1 <= s.length <= 105
  • s consists only of letters of the English alphabet in uppercase and lowercase.

代码结果

运行时间: 72 ms, 内存: 17.4 MB


/*
题目思路:
1. 使用流操作提取和排序元音字母。
2. 使用列表保存元音字母的位置。
3. 构建新的字符串,将排序后的元音字母放在相应的位置。
*/

import java.util.*;
import java.util.stream.*;

public class Solution {
    public String rearrangeVowels(String s) {
        String vowels = "aeiouAEIOU";
        List<Character> sortedVowels = s.chars()
                .filter(c -> vowels.indexOf(c) != -1)
                .mapToObj(c -> (char) c)
                .sorted()
                .collect(Collectors.toList());

        Iterator<Character> vowelIterator = sortedVowels.iterator();

        StringBuilder result = new StringBuilder();
        for (char c : s.toCharArray()) {
            if (vowels.indexOf(c) != -1) {
                result.append(vowelIterator.next());
            } else {
                result.append(c);
            }
        }

        return result.toString();
    }
}

解释

方法:

该题解的核心思路是首先创建一个与输入字符串 `s` 等长的列表 `ans`,用于存储最终结果。接着,使用一个布尔列表 `rem` 来标记每个位置的字符是否为元音字母。同时,创建一个集合 `aei` 存储所有元音字母的小写和大写形式,用于快速判断某个字符是否为元音。在遍历字符串 `s` 的过程中,如果发现元音字母,则在 `rem` 中相应位置标记为 `True`,并将该元音字母添加到列表 `col` 中。遍历完成后,对 `col` 进行排序,按照 ASCII 值逆序排序。最后,再次遍历字符串,根据 `rem` 中的标记,从 `col` 中取出排序后的元音字母填充到 `ans` 中的相应位置。最终通过 `join` 方法将列表 `ans` 转换为字符串形式返回。

时间复杂度:

O(n + v log v)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么选择使用布尔列表`rem`来标记字符位置是否为元音,而不是直接在原字符串`s`上进行修改?
使用布尔列表`rem`来标记元音位置的原因是为了避免在处理字符串`s`时进行复杂的字符替换操作。字符串在Python中是不可变的,因此直接修改字符串会导致每次修改都生成一个新的字符串对象,这样不仅效率低下,而且会增加额外的空间复杂度。通过使用布尔列表`rem`和另外一个列表`ans`来分别处理元音和辅音的位置,可以在`ans`中直接替换元音位置,这样处理更加高效且清晰。
🦆
在`col.sort(key=lambda x: ord(x), reverse=True)`这一步中,为什么选择按ASCII值逆序排序元音字母,而题目要求是非递减顺序?
这是题解中的一个错误。题目要求元音字母应该按照ASCII值的非递减顺序排列,即从小到大排序。在题解中,通过`reverse=True`实际上进行了逆序排序,这与题目要求相反。应该将`reverse=True`改为`reverse=False`或直接去除`reverse`参数,以实现正确的排序顺序。
🦆
使用`pop()`方法从列表末尾取出元音字母填充到`ans`中,这种方法是否会影响到最终字符串的元音字母顺序,尤其是当元音字母排序后相同ASCII值的元音字母如何保证它们的相对位置不变?
使用`pop()`方法确实会从列表末尾取出元音字母,这本身不会影响到元音字母的顺序,因为在填充之前已经对元音字母进行了排序。然而,如果存在相同ASCII值的元音字母,使用`pop()`取出时会按照**后进先出**的顺序,这可能会导致相同ASCII值的元音字母在最终字符串中位置与原始输入相比发生变化。为保持相同ASCII值的元音字母的相对位置不变,应当从列表前端开始取元音字母填充,或者在排序时结合其原始位置信息进行稳定排序(即保证排序稳定性)。

相关问题