题目描述
给定一个字符串,逐个翻转字符串中的每个单词。
示例:
输入: ["t","h","e"," ","s","k","y"," ","i","s"," ","b","l","u","e"]
输出: ["b","l","u","e"," ","i","s"," ","s","k","y"," ","t","h","e"]
注意:
单词的定义是不包含空格的一系列字符
输入字符串中不会包含前置或尾随的空格
单词与单词之间永远是以单个空格隔开的
进阶:
使用 O(1) 额外空间复杂度的原地解法
数据结构
- 字符串、字符数组
算法思维
- 遍历、逆序、双指针
解题要点
- 如何优化实现一个字符串中的单词顺序的反转
解题思路
一. Comprehend 理解题意
- 每个单词内部字符的顺序不变
- 单词顺序改变
- 操作对象由 String 变成 char[]
二. Choose 选择数据结构与算法
暴力解法:双指针 + 新数组
- 数据结构:指针、字符数组
- 算法思维:遍历、逆序、双指针
三. Code 编码实现基本解法
class Solution {
/*
* 双指针 + 新数组
* */
public void reverseWords(char[] s) {
int len = s.length;
StringBuffer sb = new StringBuffer();
int left = 0, right = len - 1;
for (int i = len - 1; i >= 0; i--) {
if (s[i] == ' ') {
left = i + 1;
while (left <= right) {
sb.append(s[left++]);
}
sb.append(' ');
right = i - 1;
}
if (i == 0) {
left = 0;
while (left <= right) {
sb.append(s[left++]);
}
}
}
char[] chars = sb.toString().toCharArray();
for (int j = 0; j < len; j++) {
s[j] = chars[j];
}
}
}
执行耗时:3 ms,击败了 23.58% 的Java用户
内存消耗:47.2 MB,击败了 5.18% 的Java用户
时间复杂度:O(n) -- 两次字符数组的遍历 O(n),一次字符数组赋值 O(n)
空间复杂度:O(n) -- 一个缓冲区 O(n),一个新字符数组 O(n)
四. Consider 思考更优解
改变算法思维
- 本题难点在于:如何反转单词在字符串中的顺序?
可以先反转整个字符串,再逐个单词反转字符
或者先逐个单词反转字符,再反转整个字符串
五. Code 编码实现最优解
优化解法:双翻法
class Solution {
/*
* 双翻法:先逐个单词翻转字符,再翻转整个字符串
* */
public void reverseWords(char[] s) {
//0.非空判断
if (s == null || s.length == 0) return;
int len = s.length;
int left = 0, right = 0; //左右指针
//1.遍历字符数组
while (right < len) {
//读取到空格时,说明读了一个单词
if (s[right] == ' ') {
reverse(s, left, right - 1); //反转单词字母
left = right + 1; //定位新的左指针
} else if (right == len - 1) { //到达末尾时,读的是最后一个单词
reverse(s, left, right); //反转最后一个单词的字母
}
right++;
}
//2.最终将整个字符串反转
reverse(s, 0, len - 1);
}
//反转整个字符数组的方法
private void reverse(char[] target, int from, int to) {
while (from < to) {
char c = target[from];
target[from] = target[to];
target[to] = c;
from++;
to--;
}
}
}
执行耗时:1 ms,击败了 99.59% 的Java用户
内存消耗:44.1 MB,击败了 83.62% 的Java用户
时间复杂度:O(n) -- 一次字符数组的遍历 O(n)
空间复杂度:O(1) -- 双指针 O(1)
六. Change 变形与延伸
=== 待续 ===
网友评论