151. 翻转字符串里的单词
这题主要就是考查字符串的解法,总体来说比较简单。
它规定了是不能利用额外空间,返回的字符串不算是额外空间,主要就是来限制使用库函数。
1. 双指针
由于不能用额外空间,所以我们需要在字符串上直接进行遍历,且是翻转字符串,所以显然我们需要从后向前遍历。
核心是:我们需要能够取出一个完整的单词,那么我们需要标记字母的起始和字母的结束——因此,自然的想到双指针,i来指示单词的开头,j来指示单词的结尾。
而本题麻烦的点在于可能两个单词之间可能存在多个空格,那么我们需要找到第一个非空格的字母,这个就是字母的结束
因此,我们利用i来从后向前进行遍历,循环跳过所有的空格,那么此时i指向的就是单词的结尾,j=i;然后i再向前走,直到i再次遇到空格/遍历到头了,表示该单词结束,那么[i+1, j]就构成了一个完整的字符串
但是需要注意,我们每次只取出了单词,单词之间还是要保留空格,这个需要我们自行添加,并且一定存在最后一个空格是无效的,最后需要删除
class Solution {
public String reverseWords(String s) {
int len = s.length();
int i = len - 1, j = len - 1; // 双指针,i代表前面的指针,j代表后面的指针
StringBuilder sb = new StringBuilder();
while(i >= 0){
while(i >= 0 && s.charAt(i) == ' ') i--;
if(i < 0) break; // 最前面存在空格,可能循环结束是因为已经遍历完成了
j = i; // 此时j指向的是单词的最后一位
while(i >= 0 && s.charAt(i) != ' ') i--;
// 结束之后i指向的是单词结束后的第一个空格
sb.append(s.substring(i + 1, j + 1));
sb.append(" ");
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
}
看题解,用到了string的库方法——s.trim()
,用来删除字符串前后的所有空格,那就不需要我们人为的删除了
收获:
- s.substring(i, j),是获取s的子字符串,范围在[i, j),且注意:substring没有大写的
- 求stringBuilder的长度也是用
sb.length()
,删除一个字符用sb.deleteCharAt(index)
2. 调用API
可以调用Java提供的API:主要参考1
- 先分割字符串,得到字符串数组——s.split(" ")
- 然后数组翻转——Collections.reverse(xxx);
- 再拼接得到结果:String.join(xxx)
class Solution {
public String reverseWords(String s) {
List<String> arr = Arrays.asList(s.trim().split("\\s+")); // 用正则表达式来匹配
Collections.reverse(arr); // 翻转,只有collections方法才能翻转
return String.join(" ", arr); // 字符串构建
}
}
参考:
- https://leetcode-cn.com/problems/reverse-words-in-a-string/solution/fan-zhuan-zi-fu-chuan-li-de-dan-ci-by-leetcode-sol/
- https://leetcode-cn.com/problems/reverse-words-in-a-string/solution/151-fan-zhuan-zi-fu-chuan-li-de-dan-ci-shuang-zh-2/