翻转单词顺序

题目

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。

示例 1:

输入: “the sky is blue”
输出: “blue is sky the”
示例 2:

输入: " hello world! "
输出: “world! hello”
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:

输入: “a good example”
输出: “example good a”
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

分析

这个题目去除空字符然后使用空格分割之后反转就可以。这里记录下Python中的Strip与Split函数的默认情况,这在NLP中很常用。

Strip([chars])函数

返回原字符串的副本,移除其中的前导和末尾字符。

chars 参数为指定要移除字符的字符串。 如果省略或为 None,则 chars 参数默认移除空白符。

实际上 chars 参数并非指定单个前缀或后缀;而是会移除参数值的所有组合:

1
2
3
4
5
6
7
>>> '   spacious   '.strip()
'spacious'
>>> 'www.example.com'.strip('cmowz.')
'example' # 把[char]中所有的字符全部移除了
这里也和下述情况一样
>>>'www.example.com'.strip('cmoz.')
'www.example'

最外侧的前导和末尾 chars 参数值将从字符串中移除。 开头端的字符的移除将在遇到一个未包含于 chars 所指定字符集的字符时停止。 类似的操作也将在结尾端发生。 例如:

1
2
3
4
5
>>> comment_string = '#....... Section 3.2.1 Issue #32 .......'
>>> comment_string.strip('.#! ')
'Section 3.2.1 Issue #32'
>>>'www.example.com\n\r\t\v\f'.strip()
'www.example.com'

注意:

  1. 该方法只能删除开头或是结尾的字符,不能删除中间部分的字符
  2. 通用换行也会被一并删除

Split()函数

返回一个由字符串内单词组成的列表,使用 sep 作为分隔字符串。 如果给出了 maxsplit,则最多进行 maxsplit 次拆分

1
2
3
print('1,2,3'.split(','))
print('1,2,3'.split(',',-1))
print('1,2,3'.split(',',1))

[‘1’, ‘2’, ‘3’] 默认和-1全部切割
[‘1’, ‘2’, ‘3’]
[‘1’, ‘2,3’] 1则将第一个分割出来

如果给出了 sep,则连续的分隔符不会被组合在一起而是被视为分隔空字符串 。 使用指定的分隔符拆分空字符串将返回 ['']

1
2
3
print("".split())
print("1,,,1".split(","))
print('1,2,,3,'.split(','))

[]
[‘1’, ‘’, ‘’, ‘1’] 连续的3个逗号被视为分割空字符串

[‘1’, ‘2’, ‘’, ‘3’, ‘’]

sep 参数可能由多个字符组成 (例如 '1<>2<>3'.split('<>') 将返回 ['1', '2', '3'])。

如果 sep 未指定或为 None,则会应用另一种拆分算法:

连续的空格会被视为单个分隔符,其结果将不包含开头或末尾的空字符串,如果字符串包含前缀或后缀空格的话。

因此,使用 None 拆分空字符串或仅包含空格的字符串将返回 []

1
2
3
4
print("".split())
print(" aaa a ".split())
print(" aaa \t\r\n a \t\r\n".split())
print("aaa\ta".split())

[]
[‘aaa’, ‘a’] # 前后的空格会被自动删除

[‘aaa’, ‘a’] # \t\r\n这些也会被删除,而且会当空格算,这些官方文档没说,找源码时发现是这些内置函数都是用C写的,也没有去深究。但是可以看出默认情况下这些通用换行字符(往下看看)会被当作和空格一样使用。
[‘aaa’, ‘a’]

splitlines()函数

返回由原字符串中各行组成的列表,在行边界的位置拆分。 结果列表中不包含行边界,除非给出了 keepends 且为真值。

这里使用universal newlines – 通用换行进行边界的判定。

表示符 描述
\n 换行
\r 回车
\r\n 回车 + 换行
\v\x0b 行制表符
\f\x0c 换表单
\x1c 文件分隔符
\x1d 组分隔符
\x1e 记录分隔符
\x85 下一行 (C1 控制码)
\u2028 行分隔符
\u2029 段分隔符

在 3.2 版更改: \v\f 被添加到行边界列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>>"One line\n".splitlines()
['One line']
>>>'Two lines\n'.split('\n')
['Two lines', '']
>>> 'ab c\n\nde fg\rkl\r\n'.splitlines()
['ab c', '', 'de fg', 'kl'] #可以看到splitlines和空格没有关系
>>> 'ab c\n\nde fg\rkl\r\n'.splitlines(keepends=True)
['ab c\n', '\n', 'de fg\r', 'kl\r\n']
print('ab c\n\nde fg\rkl\r\n\f\v'.splitlines())
print('ab c\n\nde fg\rkl\r\n\r'.splitlines())
print('abc\r\nabc\fab\x1ccab\rc'.splitlines())
['ab c', '', 'de fg', 'kl', '', '']
['ab c', '', 'de fg', 'kl', '']
['abc', 'abc', 'ab', 'cab', 'c']

代码

1
2
3
class Solution:
def reverseWords(self, s: str) -> str:
return ' '.join(s.strip().split()[::-1])

参考:

  • Python官方文档