是否有任何算法/技术可以在单次通过中完成字符串反转,时间复杂度为O(n),空间复杂度为O(1)。
答案 0 :(得分:2)
不,除非你已经知道每个单词被允许使用某种缓冲区多长时间,否则这在一次通过中是不可能的。
试一试:
HELLO SAM
^
becomes
SAM HELLO
^
如果您只知道E
(因为这是您的第一个/唯一的通行证,并且您不允许存储任何数据),您可能无法知道它需要交换到哪里目前的空间角色。到达空间并找出E
所属的位置后,再次检索E
为时已晚。
答案 1 :(得分:1)
如果我们可以按相反的顺序获取字符,并且每个字在内存中只需要O(1)
个机器字,那么在单个遍中反转字,O(n)-time,O(1)-space算法可以使用(伪代码):
def reverse_words(text):
word = [] # assume a word requires O(1) machine words
for character in reversed(text): # single pass (in reverse)
if character == ' ':
if word: # print non-empty word
print(''.join(reversed(word)), end=character)
word = []
else:
word.append(character) # O(1)-time
if word: # print the first word (in original text) if it is not empty
print(''.join(reversed(word)))
示例:
>>> reverse_words("this is a string")
string a is this
注意:每个角色都会被触摸两次:第一个 - 追加,第二个 - 打印它。要理解为什么它仍然是一次通过算法,想象而不是text
我们被赋予poplast()
函数来弹出(获取和删除)字符序列中的最后一个字符。如果它为空序列返回None
,那么循环将如下所示:
for character in iter(poplast, None): # call `poplast()` until it returns `None`
# the rest is the same as in the first loop ..
在这种情况下,我们不能对输入进行多次传递。它在第一次通过时被销毁。
是否可以更改原始文本?
是。再次 if 我们可以假设最长的字长是常数(独立于n
),即n
增长;最大字长保持不变。
从一端一次只读一个字到两个临时缓冲区。并且由于不同端的不均匀字大小而交换它们,同时跟踪未使用的端点。交换后只有一个临时缓冲区不为空(具有不完整单词的缓冲区)。填充缓冲区,直到两端遇到完整的单词或达到中心。然后重复交换。
我想不出一个优雅的实现。如果我们对输入进行随机访问,我就不会看到一次通过要求。对于不适合内存的非常大的文件,请查看tac
utility or tail -r
(BSD) 如何实现(在这种情况下,一行代替单个字)。
答案 2 :(得分:1)
如果考虑一个单词可以有最大字符数为20,我们可以实现O(1)空间,O(n)时间和单次通过:)
public static void main(String[] args) {
reverse("Hello World HaHa");
}
public static void reverse(String line) {
char[] stack = new char[20];
int index = 0;
for (int i = line.length() - 1; i >= 0; i--) {
if (line.charAt(i) != ' ') {
stack[index++] = line.charAt(i);
} else {
while (--index >= 0) {
System.out.print(stack[index]);
}
System.out.print(' ');
index = 0;
}
}
if (index > 0) {
while (--index >= 0) {
System.out.print(stack[index]);
}
}
}
注意:实际时间复杂度为2n,n是字符串的长度,但是单遍!