Easy
题目描述
给定一个字符串 s,在句子中反转每个单词中字符的顺序,同时仍保留空格和单词的初始顺序。
示例 1:
输入:s = "Let's take LeetCode contest"
输出:"s'teL ekat edoCteeL tsetnoc"
示例 2:
输入:s = "Mr Ding"
输出:"rM gniD"
约束条件:
1 <= s.length <= 5 * 10^4s包含可打印的 ASCII 字符s不包含任何前导或尾随空格s中至少有一个单词s中的所有单词都由单个空格分隔
解题思路
这道题要求我们反转字符串中每个单词内部的字符顺序,但保持单词之间的相对位置不变。
解法一:分割与重构法 最直观的方法是将字符串按空格分割成单词数组,逐个反转每个单词,然后重新组合。这种方法简单易懂,但需要额外的空间存储分割后的单词。
解法二:双指针原地反转(推荐) 更高效的方法是使用双指针技术在原字符串上进行原地操作。我们遍历字符串,找到每个单词的起始和结束位置,然后使用双指针对该单词进行反转。具体步骤:
- 用指针
start标记当前单词的起始位置 - 遍历字符串,当遇到空格或到达字符串末尾时,确定单词的结束位置
- 使用双指针对
[start, end]范围内的字符进行反转 - 更新
start为下一个单词的起始位置
这种方法的优势在于空间复杂度更低,且避免了字符串的多次拼接操作。
代码实现
class Solution {
public:
string reverseWords(string s) {
int n = s.length();
int start = 0;
for (int i = 0; i <= n; i++) {
if (i == n || s[i] == ' ') {
reverse(s.begin() + start, s.begin() + i);
start = i + 1;
}
}
return s;
}
};
class Solution:
def reverseWords(self, s: str) -> str:
s = list(s)
n = len(s)
start = 0
for i in range(n + 1):
if i == n or s[i] == ' ':
left, right = start, i - 1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
start = i + 1
return ''.join(s)
public class Solution {
public string ReverseWords(string s) {
char[] chars = s.ToCharArray();
int n = chars.Length;
int start = 0;
for (int i = 0; i <= n; i++) {
if (i == n || chars[i] == ' ') {
ReverseRange(chars, start, i - 1);
start = i + 1;
}
}
return new string(chars);
}
private void ReverseRange(char[] chars, int left, int right) {
while (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
}
}
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function(s) {
return s.split(' ').map(word => word.split('').reverse().join('')).join(' ');
};
复杂度分析
| 复杂度类型 | 分割重构法 | 双指针原地反转 |
|---|---|---|
| 时间复杂度 | O(n) | O(n) |
| 空间复杂度 | O(n) | O(1)* |
*注:对于 Python 和 JavaScript,由于字符串不可变,需要转换为字符数组,实际空间复杂度为 O(n)
相关题目
- . Reverse String II (Easy)