题目
题目传送门(点击即可)
给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
示例1
输入:s = “the sky is blue”
输出:“blue is sky the”
示例2
输入:s = “the sky is blue”
输出:“blue is sky the”
示例3
输入:s = “the sky is blue”
输出:“blue is sky the”
解题思路
法1
直接使用split函数将单词分割出来,然后将分割出来单词反过来拼接即可。如果这样,那其实不如不做这道题,他就失去了存在的意义
法2 双指针法
这里使用到两个“指针”指向一个单词,具体来说,两个指针一个指向单词开始地方,一个指向单词结束的地方,这样我们通过两个指针定位了一个单词。
那为什么要定位呢?
原因很简单,我们需要反转句子,但不反转单词,因此我们需要保证单词内各字符的有序性,通过这两个指针我们就定位了单词,因此我们只需要从后往前移动两个指针即可,这样就是实现句子反转,单词不反转。
思路
-
初始化两指针head和tail,他们分别指向单词的头尾,初始时两个均指向句子尾端
-
step 1:判断当前tail指针所指是否为空格,如果是,向前移动即head–
- 这里是保证tail在单词尾部,,因为句子内两单词空格数目不定,因此需要进行该操作。同时还需进行越界检查,这是因为再跳空格时可能越界,比如“ i love you”该句子开头存在空格,就会导致这种情况
-
step 2:根据tail更新head,即head=tail,然后head逆向移动,即head–,直到遇到空格,这样我们就通过head和tail定位了一个单词,这里有几个注意点:
- head也需要进行越界检查,比如当定位第一个单词(正序的第一个单词),他前面大概率没有空格,如果不进行检查他就会一直–,这样就会越界报错
- head后面一格到tail才是单词,因为head遇到空格才停止。因为后续涉及到提取字符串,因此这里需要搞清楚两个指针指向
-
step 3:根据两指针将单词提取出来,我这里偷懒使用了string自带的函数substring,如果不想要可以使用一个循环也可。
- 这里有个注意点是,如果用到substring(head+1,tail+1),他参数应该如像我这样,因为head在上面提到了是指向空格,他后面一个才是单词开头,tail+1则是因为substring的提取区间是左闭右开,因此需要注意
-
step 4:将单词加入到StringBuilder对象,然后在加入一个空格
- 这里我用了StringBuilder来添加单词,这样可以不用多次修改对象,算是一个trick吧
-
step 5:将tail指针移动到head处
-
重复step 1-step 5,知道head tail其一指针小于0
-
step 6:返回StringBuilder对象,这里注意转换成字符串,以及最后多加了一个空格,因为我们前面操作是加一个单词就加一个空格,而最后一个单词是不需要空格的,因此我们需要去掉。我这里用到stringBuilder.substring(0,stringBuilder.length()-1),这样首先实用substing可以得到一个字符串对象省去了转换一步,其次就是子串的范围可以让我去除那个多余空格
代码 java版
public static String reverseWords(String s) {
int head,tail;//指向单词首尾
StringBuilder stringBuilder = new StringBuilder();
tail = s.length()-1;
for(head = tail;head>=0;){ // head判断这里大于0==0说明是单个单词,不然在上轮已经反转完了
while(tail>=0&&s.charAt(tail)==' ') // 跳过空格
--tail;
if (tail<0)
break;
head = tail;
while (head>=0&&s.charAt(head)!=' ') //不是空格 指针前移 从后往前定位一个单词
head--;
stringBuilder.append(s.substring(head+1,tail+1));//head+1:head当前指向空格 tail+1:substring左闭右开
stringBuilder.append(" ");//添加空格
tail = head;//更新单词尾部 tail向前移动
}
//注意此时最后一个单词一定多加了一个字符串,因此要注意去除
return stringBuilder.substring(0,stringBuilder.length()-1);
}