问题:
难度:medium
说明:
给出一个字符串,去掉首位空格,然后把里面用空格隔开的每个单词位置都反转,然后翻转后的字符串单词之间,只隔着一个空格。
问题链接:https://leetcode.com/problems/reverse-words-in-a-string/
输入案例:
Example 1:
Input: "the sky is blue"
Output: "blue is sky the"
Example 2:
Input: " hello world! "
Output: "world! hello"
Explanation: Your reversed string should not contain leading or trailing spaces.
Example 3:
Input: "a good example"
Output: "example good a"
Explanation: You need to reduce multiple spaces between two words to a single space in the reversed string.
我的代码:
首先我注意到了,用 c 写算法的人需要用时间复杂度 O(1),这就意味着,用一个数组处理绝对可以(c语言的字符串就一数组)。然后就可以想象自己写了个 log(n) 的算法就可以了。
编译原理里面有介绍可以用:开始指针 + 向前指针,确定一个串,然后二分翻转就好。
代码思路是从:先全部逐个遍历 => 改为二分遍历 => 添加空格数量
class Solution {
public String reverseWords(String s) {
// 去空格
s = s.trim();
int space = 0;
int len = s.length();
char[] chs = s.toCharArray();
// 反转整个数组
divide(chs, 0, len, space);
int begin = 0;
boolean next = true;
for(int forward = 0;forward < len;forward ++) {
// 第一次遇到空格,就把词素反转
if(chs[forward] == ' ') {
if(next) {
divide(chs,begin,forward, space);
begin = forward + 1 - space;
next = false;
} else space ++;
} else {
next = true;
}
}
// 还有最后一个需要反转
divide(chs, begin, len, space);
return new String(chs, 0, len - space);
}
// 结合偏移量二分翻转词素
// 切一半(二分)反转词素,然后如果空格超过一半,就只反转词素长度次数(
public void divide(char[] chs, int begin, int end, int space) {
int len = end + begin;
int d = space > len >> 1 ? len - space : len >> 1;
for(int i = begin;i < d;i ++) {
char c = chs[i];
chs[i] = chs[len - i - 1];
chs[len - i - 1] = c;
}
}
}
如果没考虑空格的偏移量,就会差一点
class Solution {
public String reverseWords(String s) {
s = s.trim();
int len = s.length();
char[] chs = s.toCharArray();
divide(chs, 0, len);
int end = 0;
boolean next = true;
int space = 0;
for(int i = 0;i < len;i ++) {
if(chs[i] == ' ') {
if(next) {
divide(chs,end,i);
end = i + 1 - space;
next = false;
} else space ++;
} else {
next = true;
}
}
divide(chs, end, len);
return new String(chs, 0, len - space);
}
// 少传入了空格偏移量
public void divide(char[] chs, int begin, int end) {
int len = end + begin;
int d = len >> 1;
for(int i = begin;i < d;i ++) {
char c = chs[i];
chs[i] = chs[len - i - 1];
chs[len - i - 1] = c;
}
}
}
如果直接全部遍历,逐个翻转就更慢
class Solution {
public String reverseWords(String s) {
s = s.trim();
int len = s.length() - 1;
int begin = 0;
boolean next = true;
// 新建一个数组吃内存
char[] newChs = new char[len + 1];
int space = 1;
// 全部都进行遍历
for(int i = 0;i <= len;i ++) {
// 遇到一次空格全部进行翻转
if(s.charAt(i) == ' ') {
if(next) {
for(int j = begin;j < i;j ++) {
newChs[len - i - begin + j + space] = s.charAt(j);
}
newChs[len - i + space - 1] = ' ';
begin = i + 1;
next = false;
} else {
space ++;
begin ++;
}
} else next = true;
}
for(int j = begin;j <= len;j ++) {
newChs[j - begin + space - 1] = s.charAt(j);
}
return new String(newChs, space - 1, len + 2 - space);
}
}